[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # replace\npatreon: weishu\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: http://paypal.me/virtualxposed\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report_cn.md",
    "content": "---\nname: BUG反馈\nabout: 中文BUG反馈\n\n---\n\n**反馈BUG之前，先issue里面搜看看有没有别人已经反馈过，重复的不予处理！！**\n\n## 问题描述\n\n（请尽量详细地描述你遇到的问题）\n\n## 复现步骤\n\n（请分步骤描述如何复现这个BUG，非毕现BUG请给出如何能大概率复现的步骤）\n\n## 环境\n\n机型：\n系统版本：\nROM版本：（请区分内测版和开发版稳定版，除稳定版本外不予修复）\nXposed 插件以及插件版本：\nVirtualXposed版本：\n\n## 补充\n\n（别的需要描述的内容）\n\n**写完之后，请自己再读一遍自己写的，如果你自己都读不懂，就不用说修复了**\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\n\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\n\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\n\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\n\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request_cn.md",
    "content": "---\nname: 意见和建议\nabout: Feature中文版\n\n---\n\n**BUG反馈请不要用这个模版，否则直接关闭！！**\n\n## 场景描述\n\n(请详细和精确地表述你的使用场景)\n\n## 希望的解决方案\n\n(你希望如何解决这个问题？)\n\n## 其他信息\n\n(其他你认为有用的信息)"
  },
  {
    "path": ".github/issue-close-app.yml",
    "content": "# Comment that will be sent if an issue is judged to be closed\ncomment: \"This issue is closed because it does not meet our issue template/为方便解决问题，请使用 issue 模版提交问题。\"\nissueConfigs:\n# There can be several configs for different kind of issues.\n- content:\n# Example 1: bug report\n  - \"Expected behavior\"\n  - \"To Reproduce\"\n  - \"Describe the bug\"\n- content:\n# Example 2: feature request\n  - \"Describe the solution you'd like\"\n- content:\n  - \"问题描述\"\n  - \"复现步骤\"\n  - \"环境\"\n- content:\n  - \"场景描述\"\n  - \"希望的解决方案\""
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 20\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 7\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - bug\n  - security\n# Label to use when marking an issue as stale\nstaleLabel: wontfix\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": ".github/workflows/android.yml",
    "content": "name: Android CI\n\non: [pull_request, push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Checkout submodules\n      uses: srt32/git-actions@v0.0.3\n      with:\n        args: git submodule update --init --recursive\n    - name: set up JDK 1.8\n      uses: actions/setup-java@v1\n      with:\n        java-version: 1.8\n    - name: Build with Gradle\n      run: cd VirtualApp && ./gradlew assembleRelease\n    - name: ls\n      run: ls\n    - name: Archive production artifacts\n      uses: actions/upload-artifact@v1\n      with:\n        name: compiled\n        path: VirtualApp/app/build/\n"
  },
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n.idea\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.iml\n.idea/workspace.xml\n\n# Keystore files\n*.jks\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"VirtualApp/launcher\"]\n\tpath = VirtualApp/launcher\n\turl = https://github.com/android-hacker/Launcher3.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\nandroid:\n  components:\n    - tools\n    - build-tools-28.0.3\n    - android-27\n    - android-28\n    - extra-android-m2repository\n    - extra-android-support\n\ninstall:\n  - echo y | sdkmanager 'ndk-bundle'\n  - echo y | sdkmanager 'cmake;3.6.4111459'\n  - echo y | sdkmanager 'lldb;3.0'\n\nbefore_install:\n  - chmod +x ./VirtualApp/gradlew\n\nscript:\n  - cd VirtualApp\n  - ./gradlew assembleRelease\n"
  },
  {
    "path": "CHINESE.md",
    "content": "[![Build Status](https://travis-ci.org/android-hacker/VirtualXposed.svg?branch=exposed)](https://travis-ci.org/android-hacker/VirtualXposed)\n\n简介\n-----\n**VirtualXposed** 是基于[VirtualApp](https://github.com/asLody/VirtualApp) 和 [epic](https://github.com/tiann/epic) 在**非ROOT**环境下运行Xposed模块的实现（支持5.0~10.0)。\n\n与 Xposed 相比，目前 VirtualXposed 有两个限制：\n\n1. 不支持修改系统（可以修改普通APP中对系统API的调用），因此重力工具箱，应用控制器等无法使用。\n2. 暂不支持资源HOOK，因此资源钩子不会起任何作用；使用资源HOOK的模块，相应的功能不会生效。\n\n\n警告\n-------\n本项目使用的 VirtualApp 不允许用于商业用途，并且其内部的 VirtualApp 版本已经过时，如果有这个需求，为了贵公司的长期稳定发展，请使用商业授权，联系 Lody (imlody@foxmail.com)即可。\n\n使用\n----------\n\n## 准备\n\n首先在 [发布页面](https://github.com/android-hacker/VirtualXposed/releases) 下载最新的VAExposed安装包安装到手机。\n\n## 安装模块\n\n打开 VirtualXposed，在里面安装要使用的APP，以及相应的Xposed模块即可。\n\n注意：**所有的工作（安装Xposed模块，安装APP）必须在 VirtualXposed中**进行，否则Xposed模块不会有任何作用！比如，将微信直接安装在系统上（而非VirtualXposed中），防撤回安装在VirtualXposed中；或者把微信安装在VirtualXposed上，防撤回插件直接安装在系统上；或者两者都直接安装在系统上，**均不会起任何作用**。\n\n在VirtualXposed中安装App有两种方式：\n\n1. 直接复制已经在系统中安装好的APP，比如如果你系统中装了微信，那么可以直接复制一份。\n2. 通过外置存储直接安装APK文件；点主界面的底部按钮－添加应用，然后选择后面两个TAB即可。\n\n在VirtualXposed中安装Xposed模块，可以跟安装正常的APK一样，以上两种安装App的方式也适用于安装Xposed模块。不过，你也可以通过VirtualXposed中内置的XposedInstaller来安装和管理模块，跟通常的XposedInstaller使用方式一样；去下载页面，下载安装即可。 \n\n## 亲测可用的模块\n\n- [XPrivacyLua][xpl]: Really simple to use privacy manager for Android 6.0 Marshmallow and later.\n- [XInsta][xinsta]: Instagram module(Feed downing, stories downloading, etc).\n- [Minminguard][minminguard]: Completely remove both the ads inside apps and the empty space caused by those ads.\n- [YouTube AdAway][yta]:  Get rid of ads on the official YouTube App.\n- [微X模块][wx]: 微信模块，功能强大。\n- [畅玩微信][cwwx]: 微信模块新秀，功能丰富。\n- [微信巫师][wxws]: 微信模块，项目开源，代码优秀。\n- [MDWechat][mdwechat]: 微信美化模块，可以把微信整成MD风格。\n- [应用变量][yybl]: 可以用来进行机型修改，比如王者荣耀高帧率；QQ空间修改小尾巴等。\n- [音量增强器][ylzqq]: 网易云音乐模块，非常好用，低调。\n- [微信学英语][wxxyy]: 自动把微信消息翻译为英语，非常实用。\n- [情迁抢包][qqqb]: 微信QQ抢红包模块。\n- [微信跳一跳助手][ttzs]: 微信跳一跳游戏辅助模块。\n- [步数修改器][bsxg]: 运动步数修改模块。\n- [模拟位置][mnwz]: 虚拟定位模块，稳定好用。\n- [指纹支付][zwzf]: 对不支持指纹支付但系统本身有指纹的手机开启指纹支付的模块。\n- [QQ精简模块 2.0][qqjj]: QQ模块，不仅可以精简QQ，还能防撤回，防闪照。\n- [微信增强插件][wxzqcj]: 微信模块，VXP内最稳定的微信模块；如无特殊需求建议用这个。\n- [QX模块][qx]: QQ模块，防撤回抢红包斗图一应俱全。\n- [QQ斗图神器][qqdtsq]: 各种表情，斗图神器。\n- [微信斗图神器][wxdtsq]: 斗图神器，微信用的。\n- [大圣净化][dsjh]: 去广告神器，推荐使用。\n\n真正能用的模块远不止这么多，要用的话可以自己测试；如果你发现某些模块可以用但不在上面的列表中，欢迎给我发个PR。\n\n其他\n-------\n\n### GameGuardian\n\nVirtualXposed也支持GG修改器，如果你需要用GG，那么请使用GG专版(可以在发布页面下载，带 For_GameGuardian后缀)。\n\n[GG修改器使用视频教程](https://gameguardian.net/forum/gallery/image/437-no-root-via-virtualxposed-without-error-105-gameguardian/)\n\n### VirusTotal\n\nVirusTotal 还有一些其他的杀毒引擎检测到VirtualXposed有病毒，这一点我该不承认，而且我觉得这些愚蠢的杀毒引擎是在胡扯。请看[我的说明](https://github.com/android-hacker/VirtualXposed/issues/10).\n\n而且，VirtualXposed是开源的，你可以直接查看代码；我可以打包票，VirtualXposed本身没有做任何有害的事情（但是它确实有这个能力，所以请不要下载不明来源的Xposed插件）。\n\n如果你还是不放心，那么你可以使用 [0.8.7版本](https://github.com/android-hacker/VirtualXposed/releases/tag/0.8.7), 这个版本杀毒引擎的检测结果是安全的（简直就是扯淡）。\n\n\n支持和加入\n------------\n\n目前VirtualXposed 还不完善，如果你对非ROOT下实现Xposed感兴趣；欢迎加入！你可以通过如下方式来支持：\n\n1. 直接贡献代码，提供Feature，修复BUG！\n2. 使用你拥有的手机，安装你常用的Xposed模块，反馈不可用情况；协助帮忙解决兼容性问题！\n3. 提出体验上，功能上的建议，帮助完善VirtualXposed！\n\n致谢\n------\n\n1. [VirtualApp](https://github.com/asLody/VirtualApp)\n2. [Xposed](https://github.com/rovo89/Xposed)\n\n[wx]: http://repo.xposed.info/module/com.fkzhang.wechatxposed\n[qx]: http://repo.xposed.info/module/com.fkzhang.qqxposed\n[wxws]: https://github.com/Gh0u1L5/WechatMagician/releases\n[yybl]: https://www.coolapk.com/apk/com.sollyu.xposed.hook.model\n[ylzqq]: https://github.com/bin456789/Unblock163MusicClient-Xposed/releases\n[wxxyy]: https://www.coolapk.com/apk/com.hiwechart.translate\n[qqqb]: http://repo.xposed.info/module/cn.qssq666.redpacket\n[ttzs]: http://repo.xposed.info/module/com.emily.mmjumphelper\n[mnwz]: https://www.coolapk.com/apk/com.rong.xposed.fakelocation\n[zwzf]: https://github.com/android-hacker/Xposed-Fingerprint-pay/releases\n[bsxg]: https://www.coolapk.com/apk/com.specher.sm\n[mdwechat]: https://github.com/Blankeer/MDWechat\n[wxzqcj]:https://github.com/firesunCN/WechatEnhancement\n[qqjj]: https://www.coolapk.com/apk/me.zpp0196.qqsimple\n[qqdtsq]: https://www.coolapk.com/apk/x.hook.qqemoji\n[wxdtsq]: https://www.coolapk.com/apk/x.hook.emojihook\n[dsjh]: https://wiki.ad-gone.com/archives/32\n[xpl]: https://github.com/android-hacker/VirtualXposed/wiki/Privacy-control(XPrivacyLua)\n[minminguard]: http://repo.xposed.info/module/tw.fatminmin.xposed.minminguard\n[yta]: http://repo.xposed.info/module/ma.wanam.youtubeadaway\n[xinsta]: http://repo.xposed.info/module/com.ihelp101.instagram\n[cwwx]: http://repo.xposed.info/module/com.example.wx_plug_in3\n\n\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/android-hacker/VirtualXposed.svg?branch=exposed)](https://travis-ci.org/android-hacker/VirtualXposed)\n\n[中文文档](CHINESE.md \"中文\")\n\nIntroduction\n------------\n**VirtualXposed** is a simple App based on [VirtualApp](https://github.com/asLody/VirtualApp) and [epic](https://github.com/tiann/epic) that allows you to use an Xposed Module without needing to root, unlock the bootloader, or flash a custom system image. (Supports Android 5.0~10.0) \n\nThe only two restriction of VirtualXposed are:\n\n1. Unable to modify system, so any Module which modifies system won't be able to work properly.\n2. Currently resource hooks are not supported. (Theming modules use Resource Hooks).\n\nWarning\n-----------\n\nUsage for Commercial Purposes are not allowed!!!  Please refer to VirtualApp's [declaration](https://github.com/asLody/VirtualApp).\n\nUsage\n-------\n\n### Preparation\n\nDownload the latest APK from the [release page](https://github.com/android-hacker/VirtualXposed/releases), and install it on your Android device.\n\n### Install APP and Xposed Module\n\nOpen VirtualXposed, Click on the **Drawer Button** at the bottom of home page(Or long click the screen), add your desired APP and Xposed Module to VirtualXposed's virtual environment.\n\nNote: **All operations（installation of Xposed Module, APP）must be done in VirtualXposed**, otherwise the Xposed Module installed won't take effect. For example, if you install the YouTube app on your system (Your phone's original system, not in VirtualXposed), and then install YouTube AdAway (A YouTube Xposed Module) in VirtualXposed; or you install YouTube in VirtualXposed, and install YouTube AdAway on original system; or both of them are installed on original system, **neither of these three cases will work!**\n\n![How to install](https://raw.githubusercontent.com/tiann/arts/master/vxp_install.gif)\n\nThere are three ways to install an APP or Xposed Module to VirtualXposed:\n\n1. **Clone an installed app from your original system.** (Click Button at bottom of home page, then click Add App, the first page shows a list of installed apps.)\n2. **Install via an APK file.** (Click Button at bottom of home page, then click Add App, the second page shows APKs found in your sdcard)\n3. **Install via an external file chooser.** (Click Button at bottom of home page, then click Add App, use the floating action button to choose an APK file to install)\n\nFor Xposed Module, You can install it from Xposed Installer, too.\n\n### Activate the Xposed Module\n\nOpen Xposed Installer in VirtualXposed, go to the module fragment, check the module you want to use:\n\n![How to activate module](https://raw.githubusercontent.com/tiann/arts/master/vxp_activate.gif)\n\n### Reboot\n\nYou only need to reboot VirtualXposed, **There's no need to reboot your phone**; Just click Settings in home page of VirtualXposed, click `Reboot` button, and VirtualXposed will reboot in a blink. \n\n![How to reboot](https://raw.githubusercontent.com/tiann/arts/master/vxp_reboot.gif)\n\nSupported Modules \n-------------------------\n\nAlmost all modules except system-relevant are supported, please try it by yourself :)\n\nOthers\n-------\n\n### GameGuardian\n\nVirtualXposed also supports GameGuardian, **you should use the separate version for GameGuardian**.(Download it in release page).\n\n[Video Tutorial](https://gameguardian.net/forum/gallery/image/437-no-root-via-virtualxposed-without-error-105-gameguardian/)\n\n### VirusTotal\n\nVirusTotal might report VirtualXposed as a malware, it is stupid, you can refer to my [explanation](https://github.com/android-hacker/VirtualXposed/issues/10).\n\nAnd obviously, VirtualXposed is open source, so you can refer to the source code. I am sure that it is safe to use.\n\nIf you still couldn't believe in me, you can install version [0.8.7](https://github.com/android-hacker/VirtualXposed/releases/tag/0.8.7); VirusTotal reports this version as safe.\n\nSupport\n-----------\n\nContributions to VirtualXposed are always welcomed!!\n\nFor Developers\n--------------\n\n- [File a bug](https://github.com/android-hacker/exposed/issues)\n- [Wiki](https://github.com/android-hacker/VirtualXposed/wiki)\n- [Telegram](https://t.me/vxp_devs)\n\nCredits\n-------\n\n1. [VirtualApp](https://github.com/asLody/VirtualApp)\n2. [Xposed](https://github.com/rovo89/Xposed)\n3. [And64InlineHook](https://github.com/Rprop/And64InlineHook)\n"
  },
  {
    "path": "VirtualApp/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.idea\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": "VirtualApp/app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "VirtualApp/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nProperties properties = new Properties()\ndef localProp = file(project.rootProject.file('local.properties'))\nif (localProp.exists()) {\n    properties.load(localProp.newDataInputStream())\n}\ndef keyFile = file(properties.getProperty(\"keystore.path\") ?: \"/tmp/does_not_exist\")\n\nandroid {\n    signingConfigs {\n        config {\n            keyAlias properties.getProperty(\"keystore.alias\")\n            keyPassword properties.getProperty(\"keystore.pwd\")\n            storeFile keyFile\n            storePassword properties.getProperty(\"keystore.alias_pwd\")\n        }\n    }\n\n    compileSdkVersion 28\n    buildToolsVersion '28.0.3'\n    defaultConfig {\n        applicationId \"io.va.exposed64\"\n        minSdkVersion 21\n        targetSdkVersion 23\n        versionCode 220\n        versionName \"0.22.0\"\n        multiDexEnabled false\n        android {\n            defaultConfig {\n                ndk {\n                    abiFilters \"arm64-v8a\", \"x86_64\"\n                }\n            }\n        }\n    }\n    // https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html?utm_source=android-studio\n    flavorDimensions 'main'\n    productFlavors {\n        aosp {\n            dimension 'main'\n            //matchingFallbacks ['aosp']\n            if (keyFile.exists()) {\n                signingConfig signingConfigs.config\n            }\n        }\n\n        fdroid {\n            dimension 'main'\n        }\n    }\n    sourceSets {\n        main {\n            jniLibs.srcDirs = ['libs']\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            debuggable false\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    lintOptions {\n        checkReleaseBuilds false\n        // Or, if you prefer, you can continue to check for errors in release builds,\n        // but continue the build even when errors are found:\n        abortOnError false\n    }\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    implementation project(':lib')\n    implementation project(':launcher')\n    //Android Lib\n    implementation 'com.android.support:multidex:1.0.3'\n    implementation 'com.android.support:appcompat-v7:27.1.1'\n    implementation 'com.android.support:recyclerview-v7:27.1.1'\n    implementation 'com.android.support:design:27.1.1'\n    //Promise Support\n    implementation 'org.jdeferred:jdeferred-android-aar:1.2.4'\n    // ThirdParty\n    implementation 'com.jonathanfinerty.once:once:1.0.3'\n\n    def appCenterSdkVersion = '3.0.0'\n    aospImplementation(\"com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}\")\n    aospImplementation(\"com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}\")\n\n    implementation 'com.kyleduo.switchbutton:library:1.4.6'\n    implementation 'com.allenliu.versionchecklib:library:1.8.3'\n    implementation 'com.github.medyo:android-about-page:1.2.2'\n    implementation 'moe.feng:AlipayZeroSdk:1.1'\n\n    //Glide\n    implementation ('com.github.bumptech.glide:glide:4.8.0') {\n        exclude(group: \"com.android.support\")\n    }\n    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'\n}\n"
  },
  {
    "path": "VirtualApp/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/lody/Desktop/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n-keep   class com.amap.api.maps.**{*;}\n-keep   class com.autonavi.**{*;}\n-keep   class com.amap.api.trace.**{*;}\n\n#定位\n-keep class com.amap.api.location.**{*;}\n-keep class com.amap.api.fence.**{*;}\n-keep class com.autonavi.aps.amapapi.model.**{*;}\n\n#搜索\n-keep   class com.amap.api.services.**{*;}\n\n#2D地图\n-keep class com.amap.api.maps2d.**{*;}\n-keep class com.amap.api.mapcore2d.**{*;}\n\n#导航\n-keep class com.amap.api.navi.**{*;}\n-keep class com.autonavi.**{*;}\n\n##--Glide--\n-keep class com.bumptech.glide.**{*;}\n-keep public class * implements com.bumptech.glide.module.GlideModule\n-keep public class * extends com.bumptech.glide.module.AppGlideModule\n-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {\n  **[] $VALUES;\n  public *;\n}"
  },
  {
    "path": "VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyCrashHandler.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.util.Log;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.microsoft.appcenter.crashes.Crashes;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author weishu\n * @date 2019/2/25.\n */\npublic class MyCrashHandler extends BaseCrashHandler {\n    private static final String CRASH_SP = \"vxp_crash\";\n    private static final String KEY_LAST_CRASH_TIME = \"last_crash_time\";\n    private static final String KEY_LAST_CRASH_TYPE = \"last_crash_type\";\n\n    @Override\n    public void handleUncaughtException(Thread t, Throwable e) {\n        SharedPreferences sp = VirtualCore.get().getContext().getSharedPreferences(CRASH_SP, Context.MODE_MULTI_PROCESS);\n\n        Map<String, String> properties = new HashMap<>();\n        try {\n            ApplicationInfo currentApplicationInfo = VClientImpl.get().getCurrentApplicationInfo();\n            if (currentApplicationInfo != null) {\n                String packageName = currentApplicationInfo.packageName;\n                String processName = currentApplicationInfo.processName;\n\n                properties.put(\"process\", processName);\n                properties.put(\"package\", packageName);\n\n                int userId = VUserHandle.myUserId();\n\n                properties.put(\"uid\", String.valueOf(userId));\n\n                InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(packageName, 0);\n                if (installedAppInfo != null) {\n                    PackageInfo packageInfo = installedAppInfo.getPackageInfo(userId);\n                    if (packageInfo != null) {\n                        String versionName = packageInfo.versionName;\n                        int versionCode = packageInfo.versionCode;\n\n                        properties.put(\"versionName\", versionName);\n                        properties.put(\"versionCode\", String.valueOf(versionCode));\n\n                    }\n                }\n            }\n        } catch (Throwable ignored) {\n        }\n        final String exceptionType = e.getClass().getName();\n        final long now = System.currentTimeMillis();\n\n        final long lastCrash = sp.getLong(KEY_LAST_CRASH_TIME, 0);\n        final String lastCrashType = sp.getString(KEY_LAST_CRASH_TYPE, null);\n\n        if (exceptionType.equals(lastCrashType) && (now - lastCrash) < TimeUnit.MINUTES.toMillis(1)) {\n            // continues crash, do not upload\n        } else {\n            Crashes.trackError(e, properties, null);\n        }\n\n        Log.i(TAG, \"uncaught :\" + t, e);\n\n        // must commit.\n        sp.edit().putLong(KEY_LAST_CRASH_TIME, now).putString(KEY_LAST_CRASH_TYPE, exceptionType).commit();\n\n        super.handleUncaughtException(t, e);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyVirtualInitializer.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.app.Application;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.microsoft.appcenter.AppCenter;\nimport com.microsoft.appcenter.analytics.Analytics;\nimport com.microsoft.appcenter.crashes.Crashes;\n\n/**\n * @author weishu\n * @date 2019/2/25.\n */\npublic class MyVirtualInitializer extends BaseVirtualInitializer {\n    public MyVirtualInitializer(Application application, VirtualCore core) {\n        super(application, core);\n    }\n\n    @Override\n    public void onMainProcess() {\n        AppCenter.start(application, \"bf5e74bd-3795-49bd-95c8-327db494dd11\",\n                Analytics.class, Crashes.class);\n        super.onMainProcess();\n    }\n\n    @Override\n    public void onVirtualProcess() {\n\n        // For Crash statics\n        AppCenter.start(application, \"bf5e74bd-3795-49bd-95c8-327db494dd11\",\n                Analytics.class, Crashes.class);\n\n        super.onVirtualProcess();\n\n        // Override\n        virtualCore.setCrashHandler(new MyCrashHandler());\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/fdroid/java/io/virtualapp/delegate/MyVirtualInitializer.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.app.Application;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\n/**\n * @author weishu\n * @date 2019/2/25.\n */\npublic class MyVirtualInitializer extends BaseVirtualInitializer {\n    public MyVirtualInitializer(Application application, VirtualCore core) {\n        super(application, core);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"io.virtualapp\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />\n\n    <uses-sdk tools:overrideLibrary=\"com.android.launcher3,android.support.dynamicanimation\" />\n\n    <application\n        android:name=\".XApp\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/vxp\"\n        android:theme=\"@style/LauncherTheme\"\n        tools:replace=\"android:icon,android:label\">\n\n        <meta-data\n            android:name=\"android.max_aspect\"\n            android:value=\"2.3\"\n            tools:replace=\"android:value\" />\n\n        <meta-data\n            android:name=\"android.support.VERSION\"\n            android:value=\"com.android.support:design:25.4.0\"\n            tools:replace=\"android:value\" />\n\n        <activity\n            android:name=\".splash.SplashActivity\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".home.ListAppActivity\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/Theme.AppCompat.Light.NoActionBar\" />\n\n        <activity\n            android:name=\".home.LoadingActivity\"\n            android:excludeFromRecents=\"true\"\n            android:noHistory=\"true\"\n            android:screenOrientation=\"portrait\"\n            android:taskAffinity=\"va.task.loading\"\n            android:theme=\"@style/TransparentTheme\" />\n\n        <activity\n            android:name=\".settings.AboutActivity\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/Theme.AppCompat.Light.NoActionBar\" />\n\n        <activity android:name=\".home.NewHomeActivity\" />\n\n        <activity\n            android:name=\".settings.SettingsActivity\"\n            android:label=\"@string/settings_title\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@android:style/Theme.Material.Light\" />\n\n\n        <activity\n            android:name=\".settings.RecommendPluginActivity\"\n            android:label=\"@string/settings_plugin_recommend\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/Theme.AppCompat.Light\" />\n\n        <activity\n            android:name=\".settings.AppManageActivity\"\n            android:label=\"@string/settings_app_manage_text\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/Theme.AppCompat.Light\" />\n\n        <activity\n            android:name=\".settings.TaskManageActivity\"\n            android:label=\"@string/settings_task_manage_text\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/Theme.AppCompat.Light\" />\n\n        <activity\n            android:name=\".sys.ShareBridgeActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:label=\"@string/shared_to_vxp\"\n            android:screenOrientation=\"portrait\"\n            android:taskAffinity=\"${applicationId}.share\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".sys.InstallerActivity\"\n            android:allowTaskReparenting=\"true\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:icon=\"@mipmap/ic_launcher\"\n            android:label=\"@string/app_installer_label\"\n            android:noHistory=\"true\"\n            android:taskAffinity=\"${applicationId}.installer\"\n            android:theme=\"@style/Theme.AppCompat.Light\" />\n\n        <activity-alias\n            android:name=\"vxp.installer\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:targetActivity=\".sys.InstallerActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"file\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n            </intent-filter>\n\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"content\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity-alias\n            android:name=\"vxp.launcher\"\n            android:enabled=\"false\"\n            android:exported=\"true\"\n            android:targetActivity=\".home.NewHomeActivity\">\n\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.HOME\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.MONKEY\" />\n                <category android:name=\"android.intent.category.LAUNCHER_APP\" />\n            </intent-filter>\n        </activity-alias>\n\n\n        <service\n            android:name=\".update.VAVersionService\"\n            android:enabled=\"true\"\n            android:exported=\"true\" />\n\n        <receiver\n            android:name=\".dev.CmdReceiver\"\n            android:enabled=\"true\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"${applicationId}.CMD\" />\n            </intent-filter>\n        </receiver>\n    </application>\n\n\n</manifest>\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/VCommends.java",
    "content": "package io.virtualapp;\n\n/**\n * @author Lody\n */\npublic class VCommends {\n\n\tpublic static final String TAG_NEW_VERSION = \"First launch new Version\";\n\tpublic static final String TAG_SHOW_ADD_APP_GUIDE = \"Should show add app guide\";\n\n\tpublic static final int REQUEST_SELECT_APP = 5;\n\n\tpublic static final String EXTRA_APP_INFO_LIST = \"va.extra.APP_INFO_LIST\";\n\n\tpublic static final String TAG_ASK_INSTALL_GMS = \"va.extra.ASK_INSTALL_GMS\";\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/XApp.java",
    "content": "package io.virtualapp;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.NativeEngine;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.stub.VASettings;\n\nimport io.virtualapp.delegate.MyVirtualInitializer;\n\n/**\n * @author Lody\n */\npublic class XApp extends Application {\n\n    private static final String TAG = \"XApp\";\n\n    public static final String XPOSED_INSTALLER_PACKAGE = \"de.robv.android.xposed.installer\";\n\n    private static XApp gApp;\n\n    public static XApp getApp() {\n        return gApp;\n    }\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        gApp = this;\n        super.attachBaseContext(base);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            NativeEngine.disableJit(Build.VERSION.SDK_INT);\n        }\n        VASettings.ENABLE_IO_REDIRECT = true;\n        VASettings.ENABLE_INNER_SHORTCUT = false;\n        try {\n            VirtualCore.get().startup(base);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        VirtualCore virtualCore = VirtualCore.get();\n        virtualCore.initialize(new MyVirtualInitializer(this, virtualCore));\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/BasePresenter.java",
    "content": "package io.virtualapp.abs;\n\n/**\n * @author Lody\n */\npublic interface BasePresenter {\n\tvoid start();\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/BaseView.java",
    "content": "package io.virtualapp.abs;\n\nimport android.app.Activity;\nimport android.content.Context;\n\n/**\n * @author Lody\n */\npublic interface BaseView<T> {\n    Activity getActivity();\n    Context getContext();\n\tvoid setPresenter(T presenter);\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/Callback.java",
    "content": "package io.virtualapp.abs;\n\n/**\n * @author Lody\n */\n\npublic interface Callback<T> {\n    void callback(T result);\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/ui/VActivity.java",
    "content": "package io.virtualapp.abs.ui;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.support.annotation.IdRes;\nimport android.support.v4.app.Fragment;\nimport android.support.v7.app.AppCompatActivity;\n\nimport org.jdeferred.android.AndroidDeferredManager;\n\nimport io.virtualapp.abs.BaseView;\n\n/**\n * @author Lody\n */\npublic class VActivity extends AppCompatActivity {\n\n    /**\n     * Implement of {@link BaseView#getActivity()}\n     */\n    public Activity getActivity() {\n        return this;\n    }\n\n    /**\n     * Implement of {@link BaseView#getContext()} ()}\n     */\n    public Context getContext() {\n        return this;\n    }\n\n    protected AndroidDeferredManager defer() {\n        return VUiKit.defer();\n    }\n\n    public Fragment findFragmentById(@IdRes int id) {\n        return getSupportFragmentManager().findFragmentById(id);\n    }\n\n    public void replaceFragment(@IdRes int id, Fragment fragment) {\n        getSupportFragmentManager().beginTransaction().replace(id, fragment).commit();\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/ui/VFragment.java",
    "content": "package io.virtualapp.abs.ui;\n\nimport org.jdeferred.android.AndroidDeferredManager;\n\nimport android.app.Activity;\nimport android.support.v4.app.Fragment;\n\nimport io.virtualapp.abs.BasePresenter;\n\n/**\n * @author Lody\n */\npublic class VFragment<T extends BasePresenter> extends Fragment {\n\n\tprotected T mPresenter;\n\n\tpublic T getPresenter() {\n\t\treturn mPresenter;\n\t}\n\n\tpublic void setPresenter(T presenter) {\n\t\tthis.mPresenter = presenter;\n\t}\n\n\tprotected AndroidDeferredManager defer() {\n\t\treturn VUiKit.defer();\n\t}\n\n\tpublic void finishActivity() {\n\t\tActivity activity = getActivity();\n\t\tif (activity != null) {\n\t\t\tactivity.finish();\n\t\t}\n\t}\n\n\tpublic void destroy() {\n\t\tfinishActivity();\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/abs/ui/VUiKit.java",
    "content": "package io.virtualapp.abs.ui;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.util.TypedValue;\n\nimport org.jdeferred.android.AndroidDeferredManager;\n\n/**\n * @author Lody\n *         <p>\n *         A set of tools for UI.\n */\npublic class VUiKit {\n\tprivate static final AndroidDeferredManager gDM = new AndroidDeferredManager();\n\tprivate static final Handler gUiHandler = new Handler(Looper.getMainLooper());\n\n\tpublic static AndroidDeferredManager defer() {\n\t\treturn gDM;\n\t}\n\n\tpublic static int dpToPx(Context context, int dp) {\n\t\treturn (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,\n\t\t\t\tcontext.getResources().getDisplayMetrics());\n\t}\n\n\tpublic static void post(Runnable r) {\n\t\tgUiHandler.post(r);\n\t}\n\n\tpublic static void postDelayed(long delay, Runnable r) {\n\t\tgUiHandler.postDelayed(r, delay);\n\t}\n\n\tpublic static void sleep(long time) {\n\t\ttry {\n\t\t\tThread.sleep(time);\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/BaseCrashHandler.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.annotation.SuppressLint;\nimport android.os.Looper;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.CrashHandler;\n\n/**\n * author: weishu on 18/3/10.\n */\npublic class BaseCrashHandler implements CrashHandler {\n\n    protected static final String TAG = \"XApp\";\n\n    @SuppressLint(\"ApplySharedPref\")\n    @Override\n    public void handleUncaughtException(Thread t, Throwable e) {\n\n\n        if (t == Looper.getMainLooper().getThread()) {\n            System.exit(0);\n        } else {\n            Log.e(TAG, \"ignore uncaught exception of sub thread: \" + t);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/BaseVirtualInitializer.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.app.Application;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.os.VEnvironment;\n\nimport jonathanfinerty.once.Once;\nimport me.weishu.exposed.LogcatService;\n\nimport static io.virtualapp.XApp.XPOSED_INSTALLER_PACKAGE;\n\n/**\n * @author weishu\n * @date 2019/2/25.\n */\npublic class BaseVirtualInitializer extends VirtualCore.VirtualInitializer {\n\n    protected Application application;\n    protected VirtualCore virtualCore;\n\n    public BaseVirtualInitializer(Application application, VirtualCore core) {\n        this.application = application;\n        this.virtualCore = core;\n    }\n\n    @Override\n    public void onMainProcess() {\n        Once.initialise(application);\n    }\n\n    @Override\n    public void onVirtualProcess() {\n\n        virtualCore.setCrashHandler(new BaseCrashHandler());\n\n        //listener components\n        virtualCore.setComponentDelegate(new MyComponentDelegate());\n        //fake phone imei,macAddress,BluetoothAddress\n        virtualCore.setPhoneInfoDelegate(new MyPhoneInfoDelegate());\n        //fake task description's icon and title\n        virtualCore.setTaskDescriptionDelegate(new MyTaskDescDelegate());\n\n        // ensure the logcat service alive when every virtual process start.\n        LogcatService.start(application, VEnvironment.getDataUserPackageDirectory(0, XPOSED_INSTALLER_PACKAGE));\n    }\n\n    @Override\n    public void onServerProcess() {\n        virtualCore.setAppRequestListener(new MyAppRequestListener(application));\n        virtualCore.addVisibleOutsidePackage(\"com.tencent.mobileqq\");\n        virtualCore.addVisibleOutsidePackage(\"com.tencent.mobileqqi\");\n        virtualCore.addVisibleOutsidePackage(\"com.tencent.minihd.qq\");\n        virtualCore.addVisibleOutsidePackage(\"com.tencent.qqlite\");\n        virtualCore.addVisibleOutsidePackage(\"com.facebook.katana\");\n        virtualCore.addVisibleOutsidePackage(\"com.whatsapp\");\n        virtualCore.addVisibleOutsidePackage(\"com.tencent.mm\");\n        virtualCore.addVisibleOutsidePackage(\"com.immomo.momo\");\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/MyAppRequestListener.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport java.io.File;\n\nimport io.virtualapp.sys.InstallerActivity;\n\n/**\n * @author Lody\n */\n\npublic class MyAppRequestListener implements VirtualCore.AppRequestListener {\n\n    private final Context context;\n\n    public MyAppRequestListener(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void onRequestInstall(String path) {\n        try {\n            Intent t = new Intent(context, InstallerActivity.class);\n            t.setDataAndType(Uri.fromFile(new File(path)), \"application/vnd.android.package-archive\");\n            t.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            context.startActivity(t);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onRequestUninstall(String pkg) {\n        Toast.makeText(context, \"Uninstall: \" + pkg, Toast.LENGTH_SHORT).show();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/MyComponentDelegate.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.Intent;\n\nimport com.lody.virtual.client.hook.delegate.ComponentDelegate;\nimport com.lody.virtual.helper.utils.Reflect;\n\nimport java.io.File;\n\n\npublic class MyComponentDelegate implements ComponentDelegate {\n\n    @Override\n    public void beforeApplicationCreate(Application application) {\n\n    }\n\n    @Override\n    public void afterApplicationCreate(Application application) {\n\n    }\n\n    @Override\n    public void beforeActivityCreate(Activity activity) {\n\n    }\n\n    @Override\n    public void beforeActivityResume(Activity activity) {\n\n    }\n\n    @Override\n    public void beforeActivityPause(Activity activity) {\n\n    }\n\n    @Override\n    public void beforeActivityDestroy(Activity activity) {\n\n    }\n\n    @Override\n    public void afterActivityCreate(Activity activity) {\n\n    }\n\n    @Override\n    public void afterActivityResume(Activity activity) {\n\n    }\n\n    @Override\n    public void afterActivityPause(Activity activity) {\n\n    }\n\n    @Override\n    public void afterActivityDestroy(Activity activity) {\n\n    }\n\n    @Override\n    public void onSendBroadcast(Intent intent) {\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/MyPhoneInfoDelegate.java",
    "content": "package io.virtualapp.delegate;\n\nimport com.lody.virtual.client.hook.delegate.PhoneInfoDelegate;\n\n\n/**\n * Fake the Device ID.\n */\npublic class MyPhoneInfoDelegate implements PhoneInfoDelegate {\n\n    @Override\n    public String getDeviceId(String oldDeviceId, int userId) {\n        return oldDeviceId;\n    }\n\n    @Override\n    public String getBluetoothAddress(String oldAddress, int userId) {\n        return oldAddress;\n    }\n\n    @Override\n    public String getMacAddress(String oldAddress, int userId) {\n        return oldAddress;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/delegate/MyTaskDescDelegate.java",
    "content": "package io.virtualapp.delegate;\n\nimport android.annotation.TargetApi;\nimport android.app.ActivityManager;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.delegate.TaskDescriptionDelegate;\nimport com.lody.virtual.os.VUserManager;\n\n\n/**\n * Patch the task description with the (Virtual) user name\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class MyTaskDescDelegate implements TaskDescriptionDelegate {\n    @Override\n    public ActivityManager.TaskDescription getTaskDescription(ActivityManager.TaskDescription oldTaskDescription) {\n        if (oldTaskDescription == null) {\n            return null;\n        }\n        String labelPrefix = \"[\" + VUserManager.get().getUserName() + \"] \";\n        String oldLabel = oldTaskDescription.getLabel() != null ? oldTaskDescription.getLabel() : \"\";\n\n        if (!oldLabel.startsWith(labelPrefix)) {\n            // Is it really necessary?\n            return new ActivityManager.TaskDescription(labelPrefix + oldTaskDescription.getLabel(), oldTaskDescription.getIcon(), oldTaskDescription.getPrimaryColor());\n        } else {\n            return oldTaskDescription;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/dev/CmdReceiver.java",
    "content": "package io.virtualapp.dev;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.remote.InstallResult;\n\nimport io.virtualapp.BuildConfig;\nimport io.virtualapp.home.LoadingActivity;\n\n/**\n * author: weishu on 18/2/23.\n */\n\npublic class CmdReceiver extends BroadcastReceiver {\n\n    private static final String ACTION = BuildConfig.APPLICATION_ID + \".CMD\";\n    private static final String KEY_CMD = \"cmd\";\n    private static final String KEY_PKG = \"pkg\";\n    private static final String KEY_UID = \"uid\";\n\n    private static final String CMD_UPDATE = \"update\";\n    private static final String CMD_REBOOT = \"reboot\";\n    private static final String CMD_LAUNCH = \"launch\";\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        String action = intent.getAction();\n        if (!ACTION.equalsIgnoreCase(action)) {\n            return;\n        }\n\n        String cmd = intent.getStringExtra(KEY_CMD);\n        if (TextUtils.isEmpty(cmd)) {\n            showTips(context, \"No cmd found!\");\n            return;\n        }\n\n        if (CMD_REBOOT.equalsIgnoreCase(cmd)) {\n            VirtualCore.get().killAllApps();\n            showTips(context, \"Reboot Success!!\");\n            return;\n        }\n\n        if (CMD_UPDATE.equalsIgnoreCase(cmd)) {\n            String pkg = intent.getStringExtra(KEY_PKG);\n            if (TextUtils.isEmpty(pkg)) {\n                showTips(context, \"Please tell me the update package!!\");\n                return;\n            }\n\n            PackageManager packageManager = context.getPackageManager();\n            if (packageManager == null) {\n                showTips(context, \"system error, update failed!\");\n                return;\n            }\n\n            try {\n                ApplicationInfo applicationInfo = packageManager.getApplicationInfo(pkg, 0);\n                String apkPath = applicationInfo.sourceDir;\n                InstallResult installResult = VirtualCore.get().installPackage(apkPath, InstallStrategy.UPDATE_IF_EXIST);\n                if (installResult.isSuccess) {\n                    if (installResult.isUpdate) {\n                        showTips(context, \"Update \" + pkg + \" Success!!\");\n                    }\n                } else {\n                    showTips(context, \"Update \" + pkg + \" failed: \" + installResult.error);\n                }\n            } catch (PackageManager.NameNotFoundException e) {\n                showTips(context, \"Can not found \" + pkg + \" outside!\");\n            }\n        } else if (CMD_LAUNCH.equalsIgnoreCase(cmd)) {\n            String pkg = intent.getStringExtra(KEY_PKG);\n            if (TextUtils.isEmpty(pkg)) {\n                showTips(context, \"Please tell me the launch package!!\");\n                return;\n            }\n            String uid = intent.getStringExtra(KEY_UID);\n            int userId = 0;\n            if (!TextUtils.isEmpty(uid)){\n                try {\n                    userId = Integer.parseInt(uid);\n                }catch (NumberFormatException e){\n                    e.printStackTrace();\n                }\n            }\n            LoadingActivity.launch(context, pkg, userId);\n\n\n        }\n    }\n\n    private void showTips(Context context, String tips) {\n        Toast.makeText(context, tips, Toast.LENGTH_SHORT).show();\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/glide/GlideUtils.java",
    "content": "package io.virtualapp.glide;\n\nimport android.content.Context;\nimport android.support.annotation.DrawableRes;\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\nimport static io.virtualapp.glide.PackageIconResourceLoader.DATA_PACKAGE_FILE_PATH_PREFIX;\nimport static io.virtualapp.glide.PackageIconResourceLoader.DATA_PACKAGE_PREFIX;\n\n/**\n * Created by Windy on 2018/10/25\n */\npublic class GlideUtils {\n\n    public static void loadInstalledPackageIcon(Context context, String packageName, ImageView target, @DrawableRes int placeHolder) {\n        GlideApp.with(context)\n                .load(DATA_PACKAGE_PREFIX + packageName)\n                .placeholder(placeHolder)\n                .diskCacheStrategy(DiskCacheStrategy.NONE)\n                .into(target);\n    }\n\n    public static void loadPackageIconFromApkFile(Context context, String apkFilePath, ImageView target, @DrawableRes int placeHolder) {\n        GlideApp.with(context)\n                .load(DATA_PACKAGE_FILE_PATH_PREFIX + apkFilePath)\n                .placeholder(placeHolder)\n                .diskCacheStrategy(DiskCacheStrategy.NONE)\n                .into(target);\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/glide/MyGlideModule.java",
    "content": "package io.virtualapp.glide;\n\nimport android.content.Context;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.GlideBuilder;\nimport com.bumptech.glide.Registry;\nimport com.bumptech.glide.annotation.GlideModule;\nimport com.bumptech.glide.load.engine.cache.LruResourceCache;\nimport com.bumptech.glide.load.engine.cache.MemorySizeCalculator;\nimport com.bumptech.glide.module.AppGlideModule;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.InputStream;\n\n/**\n * Created by Windy on 2018/10/25\n */\n@GlideModule\npublic class MyGlideModule extends AppGlideModule {\n    @Override\n    public void applyOptions(Context context, GlideBuilder builder) {\n        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)\n                .build();\n        builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize() / 2));\n\n        VLog.i(\"MyGlideModule\", \"applyOptions\");\n    }\n\n    @Override\n    public boolean isManifestParsingEnabled() {\n        return false;\n    }\n\n    @Override\n    public void registerComponents(Context context, Glide glide, Registry registry) {\n        super.registerComponents(context, glide, registry);\n        registry.prepend(String.class, InputStream.class, new PackageIconResourceLoaderFactory(context));\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/glide/PackageIconResourceDataFetcher.java",
    "content": "package io.virtualapp.glide;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.support.annotation.NonNull;\n\nimport com.bumptech.glide.Priority;\nimport com.bumptech.glide.load.DataSource;\nimport com.bumptech.glide.load.data.DataFetcher;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport static io.virtualapp.glide.PackageIconResourceLoader.DATA_PACKAGE_FILE_PATH_PREFIX;\nimport static io.virtualapp.glide.PackageIconResourceLoader.DATA_PACKAGE_PREFIX;\n\n/**\n * Created by Windy on 2018/10/25\n */\npublic class PackageIconResourceDataFetcher implements DataFetcher<InputStream> {\n\n    private static final String TAG = PackageIconResourceDataFetcher.class.getSimpleName();\n\n    private Context context;\n    private String packageModel;\n\n    private InputStream data;\n\n    public PackageIconResourceDataFetcher(Context context, String packageName) {\n        this.context = context.getApplicationContext();\n        this.packageModel = packageName;\n    }\n\n    @Override\n    public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {\n        try {\n            data = loadResource();\n        } catch (Exception e) {\n            VLog.e(TAG, \"Failed to load data from asset manager\", e);\n            callback.onLoadFailed(e);\n            return;\n        }\n        callback.onDataReady(data);\n    }\n\n    @Override\n    public void cleanup() {\n        if (data == null) {\n            return;\n        }\n        try {\n            data.close();\n        } catch (IOException e) {\n            // Ignored.\n        }\n    }\n\n    @Override\n    public void cancel() {\n\n    }\n\n    @NonNull\n    @Override\n    public Class<InputStream> getDataClass() {\n        return InputStream.class;\n    }\n\n    @NonNull\n    @Override\n    public DataSource getDataSource() {\n        return DataSource.LOCAL;\n    }\n\n    //load icon res accord to package name, or apk path\n    private InputStream loadResource() {\n        PackageInfo packageInfo = null;\n        Drawable drawable = null;\n        try {\n            packageInfo = getPackageInfo();\n            if (packageInfo == null) {\n                return null;\n            }\n\n            drawable = packageInfo.applicationInfo.loadIcon(context.getPackageManager());\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n        }\n        if (drawable == null) {\n            return null;\n        }\n        return drawableToInputStream(drawable);\n    }\n\n    private PackageInfo getPackageInfo() throws PackageManager.NameNotFoundException {\n        if (packageModel.startsWith(DATA_PACKAGE_PREFIX)) {\n            return context.getPackageManager().getPackageInfo(getPackageTrueModel(DATA_PACKAGE_PREFIX), 0);\n        } else if (packageModel.startsWith(DATA_PACKAGE_FILE_PATH_PREFIX)) {\n            return context.getPackageManager().getPackageArchiveInfo(getPackageTrueModel(DATA_PACKAGE_FILE_PATH_PREFIX), 0);\n        }\n        return null;\n    }\n\n    private String getPackageTrueModel(String prefix) {\n        return packageModel.replaceAll(prefix, \"\");\n    }\n\n    private InputStream drawableToInputStream(Drawable drawable) {\n        Bitmap bitmap = drawableToBitmap(drawable);\n        ByteArrayOutputStream stream = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); //use the compression format of your need\n        return new ByteArrayInputStream(stream.toByteArray());\n    }\n\n    private static Bitmap drawableToBitmap(Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            return ((BitmapDrawable) drawable).getBitmap();\n        }\n\n        int width = drawable.getIntrinsicWidth();\n        width = width > 0 ? width : 1;\n        int height = drawable.getIntrinsicHeight();\n        height = height > 0 ? height : 1;\n\n        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());\n        drawable.draw(canvas);\n\n        return bitmap;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/glide/PackageIconResourceLoader.java",
    "content": "package io.virtualapp.glide;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport com.bumptech.glide.load.Options;\nimport com.bumptech.glide.load.model.ModelLoader;\nimport com.bumptech.glide.signature.ObjectKey;\n\nimport java.io.InputStream;\n\n/**\n * Created by Windy on 2018/10/25\n */\npublic class PackageIconResourceLoader implements ModelLoader<String, InputStream> {\n\n    public static final String DATA_PACKAGE_PREFIX = \"data:packageName/\";\n    public static final String DATA_PACKAGE_FILE_PATH_PREFIX = \"data:packageFilePath/\";\n\n    private Context context;\n\n\n    public PackageIconResourceLoader(Context context) {\n        this.context = context;\n    }\n\n    @Nullable\n    @Override\n    public LoadData<InputStream> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {\n        return new LoadData<>(new ObjectKey(model), new PackageIconResourceDataFetcher(context, model));\n    }\n\n    @Override\n    public boolean handles(@NonNull String model) {\n        return model.startsWith(DATA_PACKAGE_PREFIX) || model.startsWith(DATA_PACKAGE_FILE_PATH_PREFIX);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/glide/PackageIconResourceLoaderFactory.java",
    "content": "package io.virtualapp.glide;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\n\nimport com.bumptech.glide.load.model.ModelLoader;\nimport com.bumptech.glide.load.model.ModelLoaderFactory;\nimport com.bumptech.glide.load.model.MultiModelLoaderFactory;\n\nimport java.io.InputStream;\n\n/**\n * Created by Windy on 2018/10/25\n */\npublic class PackageIconResourceLoaderFactory implements ModelLoaderFactory<String, InputStream> {\n\n    private Context context;\n\n    public PackageIconResourceLoaderFactory(Context context) {\n        this.context = context;\n    }\n\n    @NonNull\n    @Override\n    public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {\n        return new PackageIconResourceLoader(context);\n    }\n\n    @Override\n    public void teardown() {\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/gms/FakeGms.java",
    "content": "package io.virtualapp.gms;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.remote.InstallResult;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.utils.DialogUtil;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * @author weishu\n * @date 2018/6/9.\n */\npublic class FakeGms {\n\n    private static final String TAG = \"FakeGms\";\n\n    private static final String GMS_CONFIG_URL = \"http://vaexposed.weishu.me/gms.json\";\n\n    private static final String GMS_PKG = \"com.google.android.gms\";\n    private static final String GSF_PKG = \"com.google.android.gsf\";\n    private static final String STORE_PKG = \"com.android.vending\";\n    private static final String FAKE_GAPPS_PKG = \"com.thermatk.android.xf.fakegapps\";\n\n    private static ExecutorService executorService = Executors.newSingleThreadExecutor();\n\n    public static void uninstallGms(Activity activity) {\n        if (activity == null) {\n            return;\n        }\n\n        AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                .setTitle(R.string.uninstall_gms_title)\n                .setMessage(R.string.uninstall_gms_content)\n                .setPositiveButton(R.string.uninstall_gms_ok, ((dialog1, which1) -> {\n                    ProgressDialog dialog = new ProgressDialog(activity);\n                    dialog.show();\n                    VUiKit.defer().when(() -> {\n                        VirtualCore.get().uninstallPackage(GMS_PKG);\n                        VirtualCore.get().uninstallPackage(GSF_PKG);\n                        VirtualCore.get().uninstallPackage(STORE_PKG);\n                        VirtualCore.get().uninstallPackage(FAKE_GAPPS_PKG);\n                    }).then((v) -> {\n                        dialog.dismiss();\n                        AlertDialog hits = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                                .setTitle(R.string.uninstall_gms_title)\n                                .setMessage(R.string.uninstall_gms_success)\n                                .setPositiveButton(android.R.string.ok, null)\n                                .create();\n                        DialogUtil.showDialog(hits);\n\n                    }).fail((v) -> {\n                        dialog.dismiss();\n                    });\n\n                }))\n                .setNegativeButton(android.R.string.cancel, null)\n                .create();\n        DialogUtil.showDialog(failDialog);\n    }\n\n    public static boolean isAlreadyInstalled(Context context) {\n        if (context == null) {\n            return false;\n        }\n\n        boolean alreadyInstalled = true;\n        if (!VirtualCore.get().isAppInstalled(GMS_PKG)) {\n            alreadyInstalled = false;\n        }\n        if (!VirtualCore.get().isAppInstalled(GSF_PKG)) {\n            alreadyInstalled = false;\n        }\n        if (!VirtualCore.get().isAppInstalled(STORE_PKG)) {\n            alreadyInstalled = false;\n        }\n        if (!VirtualCore.get().isAppInstalled(FAKE_GAPPS_PKG)) {\n            alreadyInstalled = false;\n        }\n        return alreadyInstalled;\n    }\n\n    public static void installGms(Activity activity) {\n\n        if (activity == null) {\n            return;\n        }\n\n        AlertDialog alertDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                .setTitle(R.string.install_gms_title)\n                .setMessage(R.string.install_gms_content)\n                .setPositiveButton(android.R.string.ok, ((dialog, which) -> {\n                    // show a loading dialog and start install gms.\n\n                    ProgressDialog progressDialog = new ProgressDialog(activity);\n                    progressDialog.setCancelable(false);\n                    progressDialog.show();\n\n                    executorService.submit(() -> {\n                        String failMsg = installGmsInternal(activity, progressDialog);\n                        Log.i(TAG, \"install gms result: \" + failMsg);\n                        try {\n                            progressDialog.dismiss();\n                        } catch (Throwable e) {\n                            e.printStackTrace();\n                        }\n\n                        if (failMsg == null) {\n                            activity.runOnUiThread(() -> {\n                                AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                                        .setTitle(R.string.install_gms_title)\n                                        .setMessage(R.string.install_gms_success)\n                                        .setPositiveButton(android.R.string.ok, null)\n                                        .create();\n                                DialogUtil.showDialog(failDialog);\n                            });\n                        } else {\n                            activity.runOnUiThread(() -> {\n                                AlertDialog failDialog = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                                        .setTitle(R.string.install_gms_fail_title)\n                                        .setMessage(R.string.install_gms_fail_content)\n                                        .setPositiveButton(R.string.install_gms_fail_ok, ((dialog1, which1) -> {\n                                            try {\n                                                Intent t = new Intent(Intent.ACTION_VIEW);\n                                                t.setData(Uri.parse(\"https://github.com/android-hacker/VirtualXposed/wiki/Google-service-support\"));\n                                                activity.startActivity(t);\n                                            } catch (Throwable ignored) {\n                                                ignored.printStackTrace();\n                                            }\n                                        }))\n                                        .setNegativeButton(android.R.string.cancel, null)\n                                        .create();\n                                DialogUtil.showDialog(failDialog);\n                            });\n\n                        }\n                    });\n                }))\n                .setNegativeButton(android.R.string.cancel, null)\n                .create();\n\n        DialogUtil.showDialog(alertDialog);\n    }\n\n\n    private static String installGmsInternal(Activity activity, ProgressDialog dialog) {\n        File cacheDir = activity.getCacheDir();\n\n        // 下载配置文件，得到各自的URL\n        OkHttpClient client = new OkHttpClient.Builder()\n                .connectTimeout(30, TimeUnit.SECONDS)\n                .readTimeout(30, TimeUnit.SECONDS)\n                .writeTimeout(30, TimeUnit.SECONDS)\n                .build();\n\n        Request request = new Request.Builder()\n                .url(GMS_CONFIG_URL)\n                .build();\n\n        updateMessage(activity, dialog, \"Fetching gms config...\");\n        Response response;\n        try {\n            response = client.newCall(request).execute();\n        } catch (IOException e) {\n            return \"Download gms config failed, please check your network, error: 0\";\n        }\n\n        if (!response.isSuccessful()) {\n            return \"Download gms config failed, please check your network, error: 1\";\n        }\n\n        Log.i(TAG, \"response success: \" + response.code());\n        if (200 != response.code()) {\n            return \"Download gms config failed, please check your network, error: 2\";\n        }\n\n        updateMessage(activity, dialog, \"Parsing gms config...\");\n        ResponseBody body = response.body();\n        if (body == null) {\n            return \"Download gms config failed, please check your network, error: 3\";\n        }\n\n        String string = null;\n        try {\n            string = body.string();\n        } catch (IOException e) {\n            return \"Download gms config failed, please check your network, error: 4\";\n        }\n\n        JSONObject jsonObject = null;\n        try {\n            jsonObject = new JSONObject(string);\n        } catch (JSONException e) {\n            return \"Download gms config failed, please check your network, error: 5\";\n        }\n        String gmsCoreUrl = null;\n        try {\n            gmsCoreUrl = jsonObject.getString(\"gms\");\n        } catch (JSONException e) {\n            return \"Download gms config failed, please check your network, error: 6\";\n        }\n        String gmsServiceUrl = null;\n        try {\n            gmsServiceUrl = jsonObject.getString(\"gsf\");\n        } catch (JSONException e) {\n            return \"Download gms config failed, please check your network, error: 7\";\n        }\n        String storeUrl = null;\n        try {\n            storeUrl = jsonObject.getString(\"store\");\n        } catch (JSONException e) {\n            return \"Download gms config failed, please check your network, error: 8\";\n        }\n        String fakeGappsUrl = null;\n        try {\n            fakeGappsUrl = jsonObject.getString(\"fakegapps\");\n        } catch (JSONException e) {\n            return \"Download gms config failed, please check your network, error: 9\";\n        }\n\n        String yalpStoreUrl = null;\n        try {\n            yalpStoreUrl = jsonObject.getString(\"yalp\");\n        } catch (JSONException e) {\n            // ignore.\n            Log.i(TAG, \"Download gms config failed, please check your network\");\n        }\n\n        updateMessage(activity, dialog, \"config parse success!\");\n\n        File gmsCoreFile = new File(cacheDir, \"gms.apk\");\n        File gmsServiceFile = new File(cacheDir, \"gsf.apk\");\n        File storeFile = new File(cacheDir, \"store.apk\");\n        File fakeGappsFile = new File(cacheDir, \"fakegapps.apk\");\n        File yalpStoreFile = new File(cacheDir, \"yalpStore.apk\");\n\n        // clear old files.\n        if (gmsCoreFile.exists()) {\n            gmsCoreFile.delete();\n        }\n        if (gmsServiceFile.exists()) {\n            gmsServiceFile.delete();\n        }\n        if (storeFile.exists()) {\n            storeFile.delete();\n        }\n        if (fakeGappsFile.exists()) {\n            fakeGappsFile.delete();\n        }\n\n        boolean downloadResult = downloadFile(gmsCoreUrl, gmsCoreFile,\n                (progress) -> updateMessage(activity, dialog, \"download gms core...\" + progress + \"%\"));\n        if (!downloadResult) {\n            return \"Download gms config failed, please check your network, error: 10\";\n        }\n\n        downloadResult = downloadFile(gmsServiceUrl, gmsServiceFile,\n                (progress -> updateMessage(activity, dialog, \"download gms service framework proxy..\" + progress + \"%\")));\n\n        if (!downloadResult) {\n            return \"Download gms config failed, please check your network, error: 11\";\n        }\n\n        updateMessage(activity, dialog, \"download gms store...\");\n\n        downloadResult = downloadFile(storeUrl, storeFile,\n                (progress -> updateMessage(activity, dialog, \"download gms store..\" + progress + \"%\")));\n        if (!downloadResult) {\n            return \"Download gms config failed, please check your network, error: 12\";\n        }\n\n        downloadResult = downloadFile(fakeGappsUrl, fakeGappsFile,\n                (progress -> updateMessage(activity, dialog, \"download gms Xposed module..\" + progress + \"%\")));\n        if (!downloadResult) {\n            return \"Download gms config failed, please check your network, error: 13\";\n        }\n\n        if (yalpStoreUrl != null) {\n            downloadFile(yalpStoreUrl,yalpStoreFile,\n                    (progress -> updateMessage(activity, dialog, \"download yalp store..\" + progress + \"%\")));\n        }\n\n        updateMessage(activity, dialog, \"installing gms core\");\n        InstallResult installResult = VirtualCore.get().installPackage(gmsCoreFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n\n        if (!installResult.isSuccess) {\n            return \"install gms core failed: \" + installResult.error;\n        }\n\n        updateMessage(activity, dialog, \"installing gms service framework...\");\n        installResult = VirtualCore.get().installPackage(gmsServiceFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n        if (!installResult.isSuccess) {\n            return \"install gms service framework failed: \" + installResult.error;\n        }\n\n        updateMessage(activity, dialog, \"installing gms store...\");\n        installResult = VirtualCore.get().installPackage(storeFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n        if (!installResult.isSuccess) {\n            return \"install gms store failed: \" + installResult.error;\n        }\n\n        updateMessage(activity, dialog, \"installing gms Xposed module...\");\n        installResult = VirtualCore.get().installPackage(fakeGappsFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n        if (!installResult.isSuccess) {\n            return \"install gms xposed module failed: \" + installResult.error;\n        }\n\n        if (yalpStoreFile.exists()) {\n            updateMessage(activity, dialog, \"installing yalp store...\");\n            VirtualCore.get().installPackage(yalpStoreFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n        }\n\n        // Enable the Xposed module.\n        File dataDir = VEnvironment.getDataUserPackageDirectory(0, \"de.robv.android.xposed.installer\");\n        File modulePath = VEnvironment.getPackageResourcePath(FAKE_GAPPS_PKG);\n        File configDir = new File(dataDir, \"exposed_conf\" + File.separator + \"modules.list\");\n        FileWriter writer = null;\n        try {\n            writer = new FileWriter(configDir, true);\n            writer.append(modulePath.getAbsolutePath());\n            writer.flush();\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (writer != null) {\n                try {\n                    writer.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        // success!!!\n        return null;\n    }\n\n    private static void updateMessage(Activity activity, ProgressDialog dialog, String msg) {\n        if (activity == null || dialog == null || TextUtils.isEmpty(msg)) {\n            return;\n        }\n        Log.i(TAG, \"update dialog message: \" + msg);\n        activity.runOnUiThread(() -> {\n            dialog.setMessage(msg);\n        });\n    }\n\n    public interface DownloadListener {\n        void onProgress(int progress);\n    }\n\n    public static boolean downloadFile(String url, File outFile, DownloadListener listener) {\n        OkHttpClient client = new OkHttpClient();\n        Request request = new Request.Builder().url(url).build();\n        FileOutputStream fos = null;\n        try {\n            Response response = client.newCall(request).execute();\n            if (response.code() != 200) {\n                return false;\n            }\n            ResponseBody body = response.body();\n            if (body == null) {\n                return false;\n            }\n            long toal = body.contentLength();\n            long sum = 0;\n\n            InputStream inputStream = body.byteStream();\n            fos = new FileOutputStream(outFile);\n            byte[] buffer = new byte[1024];\n            int count = 0;\n            while ((count = inputStream.read(buffer)) >= 0) {\n                fos.write(buffer, 0, count);\n                sum += count;\n                int progress = (int) ((sum * 1.0) / toal * 100);\n                if (listener != null) {\n                    listener.onProgress(progress);\n                }\n            }\n            fos.flush();\n            return true;\n        } catch (IOException e) {\n            return false;\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/ListAppActivity.java",
    "content": "package io.virtualapp.home;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.design.widget.TabLayout;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.widget.Toolbar;\nimport android.view.MenuItem;\n\nimport io.virtualapp.R;\nimport io.virtualapp.VCommends;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.home.adapters.AppPagerAdapter;\n\n/**\n * @author Lody\n */\npublic class ListAppActivity extends VActivity {\n\n    private Toolbar mToolBar;\n    private TabLayout mTabLayout;\n    private ViewPager mViewPager;\n\n    public static void gotoListApp(Activity activity) {\n        Intent intent = new Intent(activity, ListAppActivity.class);\n        activity.startActivityForResult(intent, VCommends.REQUEST_SELECT_APP);\n    }\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_clone_app);\n        mToolBar = findViewById(R.id.clone_app_tool_bar);\n        mTabLayout = mToolBar.findViewById(R.id.clone_app_tab_layout);\n        mViewPager = findViewById(R.id.clone_app_view_pager);\n        mViewPager.setAdapter(new AppPagerAdapter(getSupportFragmentManager()));\n        mTabLayout.setupWithViewPager(mViewPager);\n\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/ListAppContract.java",
    "content": "package io.virtualapp.home;\n\nimport java.util.List;\n\nimport io.virtualapp.abs.BasePresenter;\nimport io.virtualapp.abs.BaseView;\nimport io.virtualapp.home.models.AppInfo;\n\n/**\n * @author Lody\n * @version 1.0\n */\n/*package*/ class ListAppContract {\n    interface ListAppView extends BaseView<ListAppPresenter> {\n\n        void startLoading();\n\n        void loadFinish(List<AppInfo> infoList);\n    }\n\n    interface ListAppPresenter extends BasePresenter {\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/ListAppFragment.java",
    "content": "package io.virtualapp.home;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.database.Cursor;\nimport android.graphics.drawable.ColorDrawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.widget.DividerItemDecoration;\nimport android.support.v7.widget.OrientationHelper;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ProgressBar;\nimport android.widget.Toast;\n\nimport com.lody.virtual.helper.compat.NativeLibraryHelperCompat;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.virtualapp.R;\nimport io.virtualapp.XApp;\nimport io.virtualapp.abs.ui.VFragment;\nimport io.virtualapp.home.adapters.CloneAppListAdapter;\nimport io.virtualapp.home.models.AppInfo;\nimport io.virtualapp.home.models.AppInfoLite;\nimport io.virtualapp.sys.Installd;\nimport io.virtualapp.widgets.DragSelectRecyclerView;\n\n\n/**\n * @author Lody\n */\npublic class ListAppFragment extends VFragment<ListAppContract.ListAppPresenter> implements ListAppContract.ListAppView {\n    private static final String KEY_SELECT_FROM = \"key_select_from\";\n    private static final int REQUEST_GET_FILE = 1;\n\n    private DragSelectRecyclerView mRecyclerView;\n    private ProgressBar mProgressBar;\n    private Button mInstallButton;\n    private CloneAppListAdapter mAdapter;\n    private View mSelectFromExternal;\n\n    public static ListAppFragment newInstance(File selectFrom) {\n        Bundle args = new Bundle();\n        if (selectFrom != null)\n            args.putString(KEY_SELECT_FROM, selectFrom.getPath());\n        ListAppFragment fragment = new ListAppFragment();\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private File getSelectFrom() {\n        Bundle bundle = getArguments();\n        if (bundle != null) {\n            String selectFrom = bundle.getString(KEY_SELECT_FROM);\n            if (selectFrom != null) {\n                return new File(selectFrom);\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_list_app, null);\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        mAdapter.saveInstanceState(outState);\n    }\n\n    private void chooseInstallWay(Runnable runnable, String path) {\n        AlertDialog alertDialog = new AlertDialog.Builder(getContext())\n                .setTitle(R.string.install_choose_way)\n                .setMessage(R.string.install_choose_content)\n                .setPositiveButton(R.string.install_choose_taichi, (dialog, which) -> {\n                    PackageManager packageManager = getActivity().getPackageManager();\n                    try {\n                        packageManager.getPackageInfo(\"me.weishu.exp\", 0);\n                        Intent intent = new Intent();\n                        intent.setComponent(new ComponentName(\"me.weishu.exp\", \"me.weishu.exp.ui.MainActivity\"));\n                        intent.putExtra(\"path\", path);\n                        startActivity(intent);\n                    } catch (PackageManager.NameNotFoundException e) {\n                        AlertDialog showInstallDialog = new AlertDialog.Builder(getContext())\n                                .setTitle(android.R.string.dialog_alert_title)\n                                .setMessage(R.string.install_taichi_not_exist)\n                                .setPositiveButton(R.string.install_go_to_install_exp, (dialog1, which1) -> {\n                                    Intent t = new Intent(Intent.ACTION_VIEW);\n                                    t.setData(Uri.parse(\"https://www.coolapk.com/apk/me.weishu.exp\"));\n                                    startActivity(t);\n                                })\n                                .create();\n                        showInstallDialog.show();\n                    } catch (Throwable e) {\n                        AlertDialog showInstallDialog = new AlertDialog.Builder(getContext())\n                                .setTitle(android.R.string.dialog_alert_title)\n                                .setMessage(R.string.install_taichi_while_old_version)\n                                .setPositiveButton(R.string.install_go_latest_exp, (dialog1, which1) -> {\n                                    Intent t = new Intent(Intent.ACTION_VIEW);\n                                    t.setData(Uri.parse(\"https://taichi.cool\"));\n                                    startActivity(t);\n                                })\n                                .create();\n                        showInstallDialog.show();\n                    }\n                    finishActivity();\n                }).setNegativeButton(\"VirtualXposed\", (dialog, which) -> {\n                    if (runnable != null) {\n                        runnable.run();\n                    }\n                    finishActivity();\n                }).setNeutralButton(R.string.what_is_exp, ((dialog, which) -> {\n                    Intent t = new Intent(Intent.ACTION_VIEW);\n                    t.setData(Uri.parse(\"https://taichi.cool\"));\n                    startActivity(t);\n                }))\n                .create();\n        try {\n            alertDialog.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState) {\n        mRecyclerView = (DragSelectRecyclerView) view.findViewById(R.id.select_app_recycler_view);\n        mProgressBar = (ProgressBar) view.findViewById(R.id.select_app_progress_bar);\n        mInstallButton = (Button) view.findViewById(R.id.select_app_install_btn);\n        mSelectFromExternal = view.findViewById(R.id.select_app_from_external);\n        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(1, OrientationHelper.VERTICAL));\n        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);\n        dividerItemDecoration.setDrawable(new ColorDrawable(0x1f000000));\n        mRecyclerView.addItemDecoration(dividerItemDecoration);\n        mAdapter = new CloneAppListAdapter(getActivity(), getSelectFrom());\n        mRecyclerView.setAdapter(mAdapter);\n        mAdapter.setOnItemClickListener(new CloneAppListAdapter.ItemEventListener() {\n            @Override\n            public void onItemClick(AppInfo info, int position) {\n                if (!NativeLibraryHelperCompat.isApk64(info.path)) {\n                    Toast.makeText(getContext(), R.string.unsupported_for_32bit_app, Toast.LENGTH_SHORT).show();\n                    return;\n                }\n                int count = mAdapter.getSelectedCount();\n                if (!mAdapter.isIndexSelected(position)) {\n                    if (count >= 9) {\n                        Toast.makeText(getContext(), R.string.install_too_much_once_time, Toast.LENGTH_SHORT).show();\n                        return;\n                    }\n                }\n                mAdapter.toggleSelected(position);\n            }\n\n            @Override\n            public boolean isSelectable(int position) {\n                return mAdapter.isIndexSelected(position) || mAdapter.getSelectedCount() < 9;\n            }\n        });\n        mAdapter.setSelectionListener(count -> {\n            mInstallButton.setEnabled(count > 0);\n            mInstallButton.setText(String.format(Locale.ENGLISH, XApp.getApp().getResources().getString(R.string.install_d), count));\n        });\n        mInstallButton.setOnClickListener(v -> {\n            Integer[] selectedIndices = mAdapter.getSelectedIndices();\n            ArrayList<AppInfoLite> dataList = new ArrayList<AppInfoLite>(selectedIndices.length);\n            for (int index : selectedIndices) {\n                AppInfo info = mAdapter.getItem(index);\n                dataList.add(new AppInfoLite(info.packageName, info.path, info.fastOpen, info.disableMultiVersion));\n            }\n\n            if (dataList.size() > 0) {\n                String path = dataList.get(0).path;\n                chooseInstallWay(() -> {\n                    Activity activity = getActivity();\n                    if (activity == null) {\n                        return;\n                    }\n                    Installd.startInstallerActivity(activity, dataList);\n                    activity.setResult(Activity.RESULT_OK);\n                }, path);\n            }\n        });\n        mSelectFromExternal.setOnClickListener(v -> {\n            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\n            intent.setType(\"application/vnd.android.package-archive\"); // apk file\n            intent.addCategory(Intent.CATEGORY_OPENABLE);\n            try {\n                startActivityForResult(intent, REQUEST_GET_FILE);\n            } catch (Throwable ignored) {\n                Toast.makeText(getActivity(), \"Error\", Toast.LENGTH_SHORT).show();\n            }\n        });\n        new ListAppPresenterImpl(getActivity(), this, getSelectFrom()).start();\n    }\n\n    @Override\n    public void startLoading() {\n        mProgressBar.setVisibility(View.VISIBLE);\n        mRecyclerView.setVisibility(View.GONE);\n    }\n\n    @Override\n    public void loadFinish(List<AppInfo> infoList) {\n        mAdapter.setList(infoList);\n        mRecyclerView.setDragSelectActive(false, 0);\n        mAdapter.setSelected(0, false);\n        mProgressBar.setVisibility(View.GONE);\n        mRecyclerView.setVisibility(View.VISIBLE);\n    }\n\n    @Override\n    public void setPresenter(ListAppContract.ListAppPresenter presenter) {\n        this.mPresenter = presenter;\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (!(requestCode == REQUEST_GET_FILE && resultCode == Activity.RESULT_OK)) {\n            return;\n        }\n        Activity current = getActivity();\n        if (current == null) {\n            return;\n        }\n\n        Uri uri = data.getData();\n        String path = getPath(getActivity(), uri);\n        if (path == null) {\n            return;\n        }\n\n        chooseInstallWay(() -> {\n            Installd.handleRequestFromFile(getActivity(), path);\n            getActivity().setResult(Activity.RESULT_OK);\n        }, path);\n    }\n\n    public static String getPath(Context context, Uri uri) {\n        if (uri == null) {\n            return null;\n        }\n        if (\"content\".equalsIgnoreCase(uri.getScheme())) {\n            String[] projection = {\"_data\"};\n            Cursor cursor = null;\n            try {\n                cursor = context.getContentResolver().query(uri, projection, null, null, null);\n                int column_index = cursor.getColumnIndexOrThrow(\"_data\");\n                if (cursor.moveToFirst()) {\n                    return cursor.getString(column_index);\n                }\n            } catch (Exception e) {\n                // Eat it  Or Log it.\n            } finally {\n                if (cursor != null) {\n                    cursor.close();\n                }\n            }\n        } else if (\"file\".equalsIgnoreCase(uri.getScheme())) {\n            return uri.getPath();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/ListAppPresenterImpl.java",
    "content": "package io.virtualapp.home;\n\nimport android.app.Activity;\n\nimport java.io.File;\n\nimport io.virtualapp.home.repo.AppDataSource;\nimport io.virtualapp.home.repo.AppRepository;\n\n/**\n * @author Lody\n */\nclass ListAppPresenterImpl implements ListAppContract.ListAppPresenter {\n\n\tprivate Activity mActivity;\n\tprivate ListAppContract.ListAppView mView;\n\tprivate AppDataSource mRepository;\n\n\tprivate File from;\n\n\tListAppPresenterImpl(Activity activity, ListAppContract.ListAppView view, File fromWhere) {\n\t\tmActivity = activity;\n\t\tmView = view;\n\t\tmRepository = new AppRepository(activity);\n\t\tmView.setPresenter(this);\n\t\tthis.from = fromWhere;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tmView.setPresenter(this);\n\t\tmView.startLoading();\n\t\tif (from == null) {\n\t\t\tmRepository.getInstalledApps(mActivity).done(mView::loadFinish);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/LoadingActivity.java",
    "content": "package io.virtualapp.home;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.models.PackageAppData;\nimport io.virtualapp.home.repo.PackageAppDataStorage;\nimport io.virtualapp.widgets.EatBeansView;\nimport jonathanfinerty.once.Once;\n\n/**\n * @author Lody\n */\n\npublic class LoadingActivity extends VActivity {\n\n    private static final String TAG = \"LoadingActivity\";\n\n    private PackageAppData appModel;\n    private EatBeansView loadingView;\n\n    private static final int REQUEST_PERMISSION_CODE = 100;\n\n    private Intent intentToLaunch;\n    private int userToLaunch;\n\n    private long start;\n\n    public static boolean launch(Context context, String packageName, int userId) {\n        Intent intent = VirtualCore.get().getLaunchIntent(packageName, userId);\n        if (intent != null) {\n            Intent loadingPageIntent = new Intent(context, LoadingActivity.class);\n            loadingPageIntent.putExtra(Constants.PASS_PKG_NAME_ARGUMENT, packageName);\n            loadingPageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            loadingPageIntent.putExtra(Constants.PASS_KEY_INTENT, intent);\n            loadingPageIntent.putExtra(Constants.PASS_KEY_USER, userId);\n            context.startActivity(loadingPageIntent);\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        start = SystemClock.elapsedRealtime();\n\n        setContentView(R.layout.activity_loading);\n        loadingView = (EatBeansView) findViewById(R.id.loading_anim);\n        int userId = getIntent().getIntExtra(Constants.PASS_KEY_USER, -1);\n        String pkg = getIntent().getStringExtra(Constants.PASS_PKG_NAME_ARGUMENT);\n        appModel = PackageAppDataStorage.get().acquire(pkg);\n        if (appModel == null) {\n            Toast.makeText(getApplicationContext(), \"Open App:\" + pkg + \" failed.\", Toast.LENGTH_SHORT).show();\n            finish();\n            return;\n        }\n\n        ImageView iconView = (ImageView) findViewById(R.id.app_icon);\n        iconView.setImageDrawable(appModel.icon);\n        TextView nameView = (TextView) findViewById(R.id.app_name);\n        nameView.setText(String.format(Locale.ENGLISH, \"Opening %s...\", appModel.name));\n        Intent intent = getIntent().getParcelableExtra(Constants.PASS_KEY_INTENT);\n        if (intent == null) {\n            finish();\n            return;\n        }\n        VirtualCore.get().setUiCallback(intent, mUiCallback);\n\n        try {\n            // 如果已经在运行了，那么直接拉起，不做任何检测。\n            boolean uiRunning = false;\n            ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);\n            if (am != null) {\n                List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();\n                for (ActivityManager.RunningAppProcessInfo runningAppProcess : runningAppProcesses) {\n                    String appProcessName = VActivityManager.get().getAppProcessName(runningAppProcess.pid);\n                    if (TextUtils.equals(appProcessName, pkg)) {\n                        uiRunning = true;\n                        break;\n                    }\n                }\n            }\n\n            VLog.i(TAG, pkg + \"is running: \" + uiRunning);\n            if (uiRunning) {\n                launchActivity(intent, userId);\n                return;\n            }\n        } catch (Throwable ignored) {\n            ignored.printStackTrace();\n        }\n\n        checkAndLaunch(intent, userId);\n    }\n\n    private void checkAndLaunch(Intent intent, int userId) {\n        final int RUNTIME_PERMISSION_API_LEVEL = android.os.Build.VERSION_CODES.M;\n\n        if (android.os.Build.VERSION.SDK_INT < RUNTIME_PERMISSION_API_LEVEL) {\n            // the device is below Android M, the permissions are granted when install, start directly\n            Log.i(TAG, \"device's api level below Android M, do not need runtime permission.\");\n            launchActivityWithDelay(intent, userId);\n            return;\n        }\n\n        // The device is above android M, support runtime permission.\n        String packageName = appModel.packageName;\n        String name = appModel.name;\n\n        // analyze permission\n        try {\n            ApplicationInfo applicationInfo = VPackageManager.get().getApplicationInfo(packageName, 0, 0);\n            int targetSdkVersion = applicationInfo.targetSdkVersion;\n            Log.i(TAG, \"target package: \" + packageName + \" targetSdkVersion: \" + targetSdkVersion);\n\n            if (targetSdkVersion >= RUNTIME_PERMISSION_API_LEVEL) {\n                Log.i(TAG, \"target package support runtime permission, launch directly.\");\n                launchActivityWithDelay(intent, userId);\n            } else {\n\n                intentToLaunch = intent;\n                userToLaunch = userId;\n\n                PackageInfo packageInfo = VPackageManager.get().getPackageInfo(packageName, PackageManager.GET_PERMISSIONS, 0);\n                String[] requestedPermissions = packageInfo.requestedPermissions;\n\n                Set<String> dangerousPermissions = new HashSet<>();\n                for (String requestedPermission : requestedPermissions) {\n                    if (VPackage.PermissionComponent.DANGEROUS_PERMISSION.contains(requestedPermission)) {\n                        // dangerous permission, check it\n                        if (ContextCompat.checkSelfPermission(this, requestedPermission) != PackageManager.PERMISSION_GRANTED) {\n                            dangerousPermissions.add(requestedPermission);\n                        } else {\n                            Log.i(TAG, \"permission: \" + requestedPermission + \" is granted, ignore.\");\n                        }\n                    }\n                }\n\n                if (dangerousPermissions.isEmpty()) {\n                    Log.i(TAG, \"all permission are granted, launch directly.\");\n                    // all permission are granted, launch directly.\n                    launchActivityWithDelay(intent, userId);\n                } else {\n                    // tell user that this app need that permission\n                    Log.i(TAG, \"request permission: \" + dangerousPermissions);\n\n                    AlertDialog alertDialog = new AlertDialog.Builder(this, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                            .setTitle(R.string.permission_tip_title)\n                            .setMessage(getResources().getString(R.string.permission_tips_content, name))\n                            .setPositiveButton(R.string.permission_tips_confirm, (dialog, which) -> {\n                                String[] permissionToRequest = dangerousPermissions.toArray(new String[dangerousPermissions.size()]);\n                                try {\n                                    ActivityCompat.requestPermissions(this, permissionToRequest, REQUEST_PERMISSION_CODE);\n                                } catch (Throwable ignored) {\n                                }\n                            })\n                            .create();\n                    try {\n                        alertDialog.show();\n                    } catch (Throwable ignored) {\n                        // BadTokenException.\n                        finish();\n                        Toast.makeText(this, getResources().getString(R.string.start_app_failed, appModel.name), Toast.LENGTH_SHORT).show();\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            Log.e(TAG, \"check permission failed: \", e);\n            launchActivityWithDelay(intent, userId);\n        }\n    }\n\n    private void launchActivityWithDelay(Intent intent, int userId) {\n        final int MAX_WAIT = 1000;\n        long delta = SystemClock.elapsedRealtime() - start;\n        long waitTime = MAX_WAIT - delta;\n\n        if (waitTime <= 0) {\n            launchActivity(intent, userId);\n        } else {\n            loadingView.postDelayed(() -> launchActivity(intent, userId), waitTime);\n        }\n    }\n\n    private void launchActivity(Intent intent, int userId) {\n        try {\n            VActivityManager.get().startActivity(intent, userId);\n        } catch (Throwable e) {\n            VLog.e(TAG, \"start activity failed:\", e);\n            Toast.makeText(getApplicationContext(), getResources().getString(R.string.start_app_failed, appModel.name), Toast.LENGTH_SHORT).show();\n            finish();\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == REQUEST_PERMISSION_CODE) {\n            boolean allGranted = true;\n            for (int grantResult : grantResults) {\n                if (grantResult == PackageManager.PERMISSION_DENIED) {\n                    allGranted = false;\n                    break;\n                }\n            }\n\n            if (allGranted) {\n                if (intentToLaunch == null) {\n                    Toast.makeText(this, getResources().getString(R.string.start_app_failed, appModel.name), Toast.LENGTH_SHORT).show();\n                    finish();\n                } else {\n                    launchActivityWithDelay(intentToLaunch, userToLaunch);\n                }\n            } else {\n                // 提示用户，targetSdkVersion < 23 无法使用运行时权限\n                Log.i(TAG, \"can not use runtime permission, you must grant all permission, otherwise the app may not work!\");\n\n                final String tag = \"permission_tips_\" + appModel.packageName.replaceAll(\"\\\\.\", \"_\");\n                // TODO find a device figuring out why some permissions are not detected.\n                if (!Once.beenDone(tag)) {\n                    AlertDialog alertDialog = new AlertDialog.Builder(this, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                            .setTitle(android.R.string.dialog_alert_title)\n                            .setMessage(getResources().getString(R.string.permission_denied_tips_content, appModel.name))\n                            .setPositiveButton(R.string.permission_tips_confirm, (dialog, which) -> {\n                                finish();\n                                Once.markDone(tag);\n                                launchActivityWithDelay(intentToLaunch, userToLaunch);\n                            })\n                            .create();\n                    try {\n                        alertDialog.show();\n                    } catch (Throwable ignored) {\n                        // BadTokenException.\n                        Toast.makeText(this, getResources().getString(R.string.start_app_failed, appModel.name), Toast.LENGTH_SHORT).show();\n                    }\n                } else {\n                    launchActivityWithDelay(intentToLaunch, userToLaunch);\n                    finish();\n                }\n            }\n        }\n    }\n\n    private final VirtualCore.UiCallback mUiCallback = new VirtualCore.UiCallback() {\n\n        @Override\n        public void onAppOpened(String packageName, int userId) throws RemoteException {\n            finish();\n        }\n\n        @Override\n        public void onOpenFailed(String packageName, int userId) throws RemoteException {\n            VUiKit.defer().when(() -> {\n            }).done((v) -> {\n                if (!isFinishing()) {\n                    Toast.makeText(getApplicationContext(), getResources().getString(R.string.start_app_failed, packageName),\n                            Toast.LENGTH_SHORT).show();\n                }\n            });\n\n            finish();\n        }\n    };\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        startAnim();\n    }\n\n    private void startAnim() {\n        if (loadingView != null) {\n            loadingView.startAnim();\n        }\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        if (loadingView != null) {\n            loadingView.stopAnim();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/NewHomeActivity.java",
    "content": "package io.virtualapp.home;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.ActivityNotFoundException;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.PowerManager;\nimport android.os.SystemClock;\nimport android.preference.PreferenceManager;\nimport android.provider.Settings;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.Toast;\n\nimport com.android.launcher3.LauncherFiles;\nimport com.google.android.apps.nexuslauncher.NexusLauncherActivity;\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.DeviceUtil;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.MD5Utils;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Method;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.settings.SettingsActivity;\nimport io.virtualapp.update.VAVersionService;\nimport io.virtualapp.utils.Misc;\nimport jonathanfinerty.once.Once;\n\nimport static io.virtualapp.XApp.XPOSED_INSTALLER_PACKAGE;\n\n/**\n * @author weishu\n * @date 18/2/9.\n */\n\npublic class NewHomeActivity extends NexusLauncherActivity {\n\n    private static final String SHOW_DOZE_ALERT_KEY = \"SHOW_DOZE_ALERT_KEY\";\n    private static final String WALLPAPER_FILE_NAME = \"wallpaper.png\";\n\n    private Handler mUiHandler;\n    private boolean mDirectlyBack = false;\n    private final AtomicBoolean checkXposedInstaller = new AtomicBoolean(true);\n\n    public static void goHome(Context context) {\n        Intent intent = new Intent(context, NewHomeActivity.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        SharedPreferences sharedPreferences = getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE);\n        super.onCreate(savedInstanceState);\n        showMenuKey();\n        mUiHandler = new Handler(getMainLooper());\n        alertForMeizu();\n        alertForDonate();\n        mDirectlyBack = sharedPreferences.getBoolean(SettingsActivity.DIRECTLY_BACK_KEY, false);\n    }\n\n    private void installXposed() {\n        if (!VirtualCore.get().isXposedEnabled()) {\n            return;\n        }\n        boolean isXposedInstalled = false;\n        try {\n            isXposedInstalled = VirtualCore.get().isAppInstalled(XPOSED_INSTALLER_PACKAGE);\n            File oldXposedInstallerApk = getFileStreamPath(\"XposedInstaller_1_31.apk\");\n            if (oldXposedInstallerApk.exists()) {\n                VirtualCore.get().uninstallPackage(XPOSED_INSTALLER_PACKAGE);\n                oldXposedInstallerApk.delete();\n                isXposedInstalled = false;\n                Log.d(TAG, \"remove xposed installer success!\");\n            }\n        } catch (Throwable e) {\n            VLog.d(TAG, \"remove xposed install failed.\", e);\n        }\n\n        if (!isXposedInstalled) {\n            ProgressDialog dialog = new ProgressDialog(this);\n            dialog.setCancelable(false);\n            dialog.setMessage(getResources().getString(R.string.prepare_xposed_installer));\n            dialog.show();\n\n            VUiKit.defer().when(() -> {\n                File xposedInstallerApk = getFileStreamPath(\"XposedInstaller_5_8.apk\");\n                if (!xposedInstallerApk.exists()) {\n                    InputStream input = null;\n                    OutputStream output = null;\n                    try {\n                        input = getApplicationContext().getAssets().open(\"XposedInstaller_3.1.5.apk_\");\n                        output = new FileOutputStream(xposedInstallerApk);\n                        byte[] buffer = new byte[1024];\n                        int length;\n                        while ((length = input.read(buffer)) > 0) {\n                            output.write(buffer, 0, length);\n                        }\n                    } catch (Throwable e) {\n                        VLog.e(TAG, \"copy file error\", e);\n                    } finally {\n                        FileUtils.closeQuietly(input);\n                        FileUtils.closeQuietly(output);\n                    }\n                }\n\n                if (xposedInstallerApk.isFile() && !DeviceUtil.isMeizuBelowN()) {\n                    try {\n                        if (\"8537fb219128ead3436cc19ff35cfb2e\".equals(MD5Utils.getFileMD5String(xposedInstallerApk))) {\n                            VirtualCore.get().installPackage(xposedInstallerApk.getPath(), InstallStrategy.TERMINATE_IF_EXIST);\n                        } else {\n                            VLog.w(TAG, \"unknown Xposed installer, ignore!\");\n                        }\n                    } catch (Throwable ignored) {\n                    }\n                }\n            }).then((v) -> {\n                dismissDialog(dialog);\n            }).fail((err) -> {\n                dismissDialog(dialog);\n            });\n        }\n    }\n\n    private static void dismissDialog(ProgressDialog dialog) {\n        if (dialog == null) {\n            return;\n        }\n        try {\n            dialog.dismiss();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (checkXposedInstaller.compareAndSet(true, false)) {\n            installXposed();\n        }\n        // check for update\n        new Handler().postDelayed(() ->\n                VAVersionService.checkUpdate(getApplicationContext(), false), 1000);\n\n        // check for wallpaper\n        setWallpaper();\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_MENU) {\n            onSettingsClicked();\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    public Activity getActivity() {\n        return this;\n    }\n\n    public Context getContext() {\n        return this;\n    }\n\n    @Override\n    public void onClickAddWidgetButton(View view) {\n        onAddAppClicked();\n    }\n\n    private void onAddAppClicked() {\n        ListAppActivity.gotoListApp(this);\n    }\n\n    private void onSettingsClicked() {\n        startActivity(new Intent(NewHomeActivity.this, SettingsActivity.class));\n    }\n\n    @Override\n    public void onClickSettingsButton(View v) {\n        onSettingsClicked();\n    }\n\n    @Override\n    protected void onClickAllAppsButton(View v) {\n        onSettingsClicked();\n    }\n\n    @Override\n    public void startVirtualActivity(Intent intent, Bundle options, int usedId) {\n        String packageName = intent.getPackage();\n        if (TextUtils.isEmpty(packageName)) {\n            ComponentName component = intent.getComponent();\n            if (component != null) {\n                packageName = component.getPackageName();\n            }\n        }\n        if (packageName == null) {\n            try {\n                startActivity(intent);\n                return;\n            } catch (Throwable ignored) {\n                // ignore\n            }\n        }\n        boolean result = LoadingActivity.launch(this, packageName, usedId);\n        if (!result) {\n            throw new ActivityNotFoundException(\"can not launch activity for :\" + intent);\n        }\n        if (mDirectlyBack) {\n            finish();\n        }\n    }\n\n    private void alertForDonate() {\n        final String TAG = \"show_donate\";\n        if (Once.beenDone(Once.THIS_APP_VERSION, TAG)) {\n            alertForDoze();\n            return;\n        }\n        AlertDialog alertDialog = new AlertDialog.Builder(getContext())\n                .setTitle(R.string.about_donate)\n                .setMessage(R.string.donate_dialog_content)\n                .setPositiveButton(android.R.string.yes, (dialog, which) -> {\n                    Misc.showDonate(this);\n                    Once.markDone(TAG);\n                })\n                .create();\n        try {\n            alertDialog.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    private void alertForMeizu() {\n        if (!DeviceUtil.isMeizuBelowN()) {\n            return;\n        }\n        boolean isXposedInstalled = VirtualCore.get().isAppInstalled(XPOSED_INSTALLER_PACKAGE);\n        if (isXposedInstalled) {\n            return;\n        }\n        mUiHandler.postDelayed(() -> {\n            AlertDialog alertDialog = new AlertDialog.Builder(getContext())\n                    .setTitle(R.string.meizu_device_tips_title)\n                    .setMessage(R.string.meizu_device_tips_content)\n                    .setPositiveButton(android.R.string.yes, (dialog, which) -> {\n                    })\n                    .create();\n            try {\n                alertDialog.show();\n            } catch (Throwable ignored) {\n            }\n        }, 2000);\n    }\n\n    private void alertForDoze() {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return;\n        }\n        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);\n        if (powerManager == null) {\n            return;\n        }\n        boolean showAlert = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(SHOW_DOZE_ALERT_KEY, true);\n        if (!showAlert) {\n            return;\n        }\n        String packageName = getPackageName();\n        boolean ignoringBatteryOptimizations = powerManager.isIgnoringBatteryOptimizations(packageName);\n        if (!ignoringBatteryOptimizations) {\n\n            mUiHandler.postDelayed(() -> {\n                AlertDialog alertDialog = new AlertDialog.Builder(getContext())\n                        .setTitle(R.string.alert_for_doze_mode_title)\n                        .setMessage(R.string.alert_for_doze_mode_content)\n                        .setPositiveButton(R.string.alert_for_doze_mode_yes, (dialog, which) -> {\n                            try {\n                                startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(\"package:\" + getPackageName())));\n                            } catch (ActivityNotFoundException ignored) {\n                                // ActivityNotFoundException on some devices.\n                                try {\n                                    startActivity(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));\n                                } catch (Throwable e) {\n                                    PreferenceManager.getDefaultSharedPreferences(getActivity())\n                                            .edit().putBoolean(SHOW_DOZE_ALERT_KEY, false).apply();\n                                }\n                            } catch (Throwable e) {\n                                PreferenceManager.getDefaultSharedPreferences(getActivity())\n                                        .edit().putBoolean(SHOW_DOZE_ALERT_KEY, false).apply();\n                            }\n                        })\n                        .setNegativeButton(R.string.alert_for_doze_mode_no, (dialog, which) ->\n                                PreferenceManager.getDefaultSharedPreferences(getActivity())\n                                        .edit().putBoolean(SHOW_DOZE_ALERT_KEY, false).apply())\n                        .create();\n                try {\n                    alertDialog.show();\n                } catch (Throwable ignored) {\n                    ignored.printStackTrace();\n                }\n            }, 1000);\n        }\n    }\n\n    private void setWallpaper() {\n        File wallpaper = getFileStreamPath(WALLPAPER_FILE_NAME);\n        if (wallpaper == null || !wallpaper.exists() || wallpaper.isDirectory()) {\n            setOurWallpaper(getResources().getDrawable(R.drawable.home_bg));\n        } else {\n            long start = SystemClock.elapsedRealtime();\n            Drawable d;\n            try {\n                d = BitmapDrawable.createFromPath(wallpaper.getPath());\n            } catch (Throwable e) {\n                Toast.makeText(getApplicationContext(), R.string.wallpaper_too_big_tips, Toast.LENGTH_SHORT).show();\n                return;\n            }\n            long cost = SystemClock.elapsedRealtime() - start;\n            if (cost > 200) {\n                Toast.makeText(getApplicationContext(), R.string.wallpaper_too_big_tips, Toast.LENGTH_SHORT).show();\n            }\n            if (d == null) {\n                setOurWallpaper(getResources().getDrawable(R.drawable.home_bg));\n            } else {\n                setOurWallpaper(d);\n            }\n        }\n    }\n\n    private void showMenuKey() {\n        try {\n            Method setNeedsMenuKey = Window.class.getDeclaredMethod(\"setNeedsMenuKey\", int.class);\n            setNeedsMenuKey.setAccessible(true);\n            int value = WindowManager.LayoutParams.class.getField(\"NEEDS_MENU_SET_TRUE\").getInt(null);\n            setNeedsMenuKey.invoke(getWindow(), value);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/adapters/AppPagerAdapter.java",
    "content": "package io.virtualapp.home.adapters;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.XApp;\nimport io.virtualapp.home.ListAppFragment;\n\n/**\n * @author Lody\n */\npublic class AppPagerAdapter extends FragmentPagerAdapter {\n    private List<String> titles = new ArrayList<>();\n    private List<File> dirs = new ArrayList<>();\n\n    public AppPagerAdapter(FragmentManager fm) {\n        super(fm);\n        titles.add(XApp.getApp().getResources().getString(R.string.clone_apps));\n        dirs.add(null);\n    }\n\n    @Override\n    public Fragment getItem(int position) {\n        return ListAppFragment.newInstance(dirs.get(position));\n    }\n\n    @Override\n    public int getCount() {\n        return titles.size();\n    }\n\n    @Override\n    public CharSequence getPageTitle(int position) {\n        return titles.get(position);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/adapters/CloneAppListAdapter.java",
    "content": "package io.virtualapp.home.adapters;\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.glide.GlideUtils;\nimport io.virtualapp.home.models.AppInfo;\nimport io.virtualapp.widgets.DragSelectRecyclerViewAdapter;\nimport io.virtualapp.widgets.LabelView;\n\n/**\n * @author Lody\n */\npublic class CloneAppListAdapter extends DragSelectRecyclerViewAdapter<CloneAppListAdapter.ViewHolder> {\n\n    private static final int TYPE_FOOTER = -2;\n    private final View mFooterView;\n    private LayoutInflater mInflater;\n    private List<AppInfo> mAppList;\n    private ItemEventListener mItemEventListener;\n\n    private Context mContext;\n    private File mFrom;\n\n\n    public CloneAppListAdapter(Context context, @Nullable File from) {\n        mContext = context;\n        mFrom = from;\n        this.mInflater = LayoutInflater.from(context);\n        mFooterView = new View(context);\n        StaggeredGridLayoutManager.LayoutParams params = new StaggeredGridLayoutManager.LayoutParams(\n                ViewGroup.LayoutParams.MATCH_PARENT, VUiKit.dpToPx(context, 60)\n        );\n        params.setFullSpan(true);\n        mFooterView.setLayoutParams(params);\n\n    }\n\n    public void setOnItemClickListener(ItemEventListener mItemEventListener) {\n        this.mItemEventListener = mItemEventListener;\n    }\n\n    public List<AppInfo> getList() {\n        return mAppList;\n    }\n\n    public void setList(List<AppInfo> models) {\n        this.mAppList = models;\n        notifyDataSetChanged();\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == TYPE_FOOTER) {\n            return new ViewHolder(mFooterView);\n        }\n        return new ViewHolder(mInflater.inflate(R.layout.item_clone_app, null));\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        if (getItemViewType(position) == TYPE_FOOTER) {\n            return;\n        }\n        super.onBindViewHolder(holder, position);\n        AppInfo info = mAppList.get(position);\n\n        if (mFrom == null) {\n            GlideUtils.loadInstalledPackageIcon(mContext, info.packageName, holder.iconView, android.R.drawable.sym_def_app_icon);\n        } else {\n            GlideUtils.loadPackageIconFromApkFile(mContext, info.path, holder.iconView, android.R.drawable.sym_def_app_icon);\n        }\n\n        holder.nameView.setText(String.format(\"%s: %s%s\", info.name, info.version, info.splitApk ? \" [S]\" : \"\"));\n        if (isIndexSelected(position)) {\n            holder.iconView.setAlpha(1f);\n            holder.appCheckView.setImageResource(R.drawable.ic_check);\n        } else {\n            holder.iconView.setAlpha(0.65f);\n            holder.appCheckView.setImageResource(R.drawable.ic_no_check);\n        }\n        if (info.cloneCount > 0) {\n            holder.labelView.setVisibility(View.VISIBLE);\n            holder.labelView.setText(info.cloneCount + 1 + \"\");\n        } else {\n            holder.labelView.setVisibility(View.INVISIBLE);\n        }\n\n        holder.itemView.setOnClickListener(v -> {\n            mItemEventListener.onItemClick(info, position);\n        });\n    }\n\n    @Override\n    public void onAttachedToRecyclerView(RecyclerView recyclerView) {\n        super.onAttachedToRecyclerView(recyclerView);\n    }\n\n    @Override\n    protected boolean isIndexSelectable(int index) {\n        return mItemEventListener.isSelectable(index);\n    }\n\n    @Override\n    public int getItemCount() {\n        return mAppList == null ? 1 : mAppList.size() + 1;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == getItemCount() - 1) {\n            return TYPE_FOOTER;\n        }\n        return super.getItemViewType(position);\n    }\n\n    public AppInfo getItem(int index) {\n        return mAppList.get(index);\n    }\n\n    public interface ItemEventListener {\n\n        void onItemClick(AppInfo appData, int position);\n\n        boolean isSelectable(int position);\n    }\n\n    class ViewHolder extends RecyclerView.ViewHolder {\n        private ImageView iconView;\n        private TextView nameView;\n        private ImageView appCheckView;\n        private LabelView labelView;\n\n        ViewHolder(View itemView) {\n            super(itemView);\n            if (itemView != mFooterView) {\n                iconView = (ImageView) itemView.findViewById(R.id.item_app_icon);\n                nameView = (TextView) itemView.findViewById(R.id.item_app_name);\n                appCheckView = (ImageView) itemView.findViewById(R.id.item_app_checked);\n                labelView = (LabelView) itemView.findViewById(R.id.item_app_clone_count);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/models/AppData.java",
    "content": "package io.virtualapp.home.models;\n\nimport android.graphics.drawable.Drawable;\n\n/**\n * @author Lody\n */\n\npublic interface AppData {\n\n    boolean isInstalling();\n\n    boolean isLoading();\n\n    boolean isFirstOpen();\n\n    Drawable getIcon();\n\n    String getName();\n\n    boolean canReorder();\n\n    boolean canLaunch();\n\n    boolean canDelete();\n\n    boolean canCreateShortcut();\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfo.java",
    "content": "package io.virtualapp.home.models;\n\nimport android.graphics.drawable.Drawable;\n\n/**\n * @author Lody\n */\n\npublic class AppInfo {\n    public String packageName;\n    public String path;\n    public boolean fastOpen;\n    public Drawable icon;\n    public CharSequence name;\n    public CharSequence version;\n    public int cloneCount;\n    public boolean disableMultiVersion;\n    public boolean splitApk;\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/models/AppInfoLite.java",
    "content": "package io.virtualapp.home.models;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class AppInfoLite implements Parcelable {\n\n    public static final Creator<AppInfoLite> CREATOR = new Creator<AppInfoLite>() {\n        @Override\n        public AppInfoLite createFromParcel(Parcel source) {\n            return new AppInfoLite(source);\n        }\n\n        @Override\n        public AppInfoLite[] newArray(int size) {\n            return new AppInfoLite[size];\n        }\n    };\n    public String packageName;\n    public String path;\n    public boolean fastOpen;\n    public boolean disableMultiVersion;\n\n    public AppInfoLite(String packageName, String path, boolean fastOpen, boolean disableMultiVersion) {\n        this.packageName = packageName;\n        this.path = path;\n        this.fastOpen = fastOpen;\n        this.disableMultiVersion = disableMultiVersion;\n    }\n\n    protected AppInfoLite(Parcel in) {\n        this.packageName = in.readString();\n        this.path = in.readString();\n        this.fastOpen = in.readByte() != 0;\n        this.disableMultiVersion = in.readByte() != 0;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.packageName);\n        dest.writeString(this.path);\n        dest.writeByte(this.fastOpen ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.disableMultiVersion ? (byte) 1 : (byte) 0);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/models/MultiplePackageAppData.java",
    "content": "package io.virtualapp.home.models;\n\nimport android.graphics.drawable.Drawable;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\n/**\n * @author Lody\n */\n\npublic class MultiplePackageAppData implements AppData {\n\n    public InstalledAppInfo appInfo;\n    public int userId;\n    public boolean isFirstOpen;\n    public boolean isInstalling;\n    public boolean isLoading;\n    public Drawable icon;\n    public String name;\n\n    public MultiplePackageAppData(PackageAppData target, int userId) {\n        this.userId = userId;\n        this.appInfo = VirtualCore.get().getInstalledAppInfo(target.packageName, 0);\n        this.isFirstOpen = !appInfo.isLaunched(userId);\n        if (target.icon != null) {\n            Drawable.ConstantState state = target.icon.getConstantState();\n            if (state != null) {\n                icon = state.newDrawable();\n            }\n        }\n        name = target.name;\n    }\n\n    @Override\n    public boolean isInstalling() {\n        return isInstalling;\n    }\n\n    @Override\n    public boolean isLoading() {\n        return isLoading;\n    }\n\n    @Override\n    public boolean isFirstOpen() {\n        return isFirstOpen;\n    }\n\n    @Override\n    public Drawable getIcon() {\n        return icon;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public boolean canReorder() {\n        return true;\n    }\n\n    @Override\n    public boolean canLaunch() {\n        return true;\n    }\n\n    @Override\n    public boolean canDelete() {\n        return true;\n    }\n\n    @Override\n    public boolean canCreateShortcut() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/models/PackageAppData.java",
    "content": "package io.virtualapp.home.models;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\n\nimport com.lody.virtual.remote.InstalledAppInfo;\n\n/**\n * @author Lody\n */\npublic class PackageAppData implements AppData {\n\n    public String packageName;\n    public String name;\n    public Drawable icon;\n    public boolean fastOpen;\n    public boolean isFirstOpen;\n    public boolean isLoading;\n    public boolean isInstalling;\n\n    public PackageAppData(Context context, InstalledAppInfo installedAppInfo) {\n        this.packageName = installedAppInfo.packageName;\n        this.isFirstOpen = !installedAppInfo.isLaunched(0);\n        loadData(context, installedAppInfo.getApplicationInfo(installedAppInfo.getInstalledUsers()[0]));\n    }\n\n    public PackageAppData(Context context, ApplicationInfo appInfo) {\n        this.packageName = appInfo.packageName;\n        loadData(context, appInfo);\n    }\n\n    private void loadData(Context context, ApplicationInfo appInfo) {\n        if (appInfo == null) {\n            return;\n        }\n        PackageManager pm = context.getPackageManager();\n        try {\n            CharSequence sequence = appInfo.loadLabel(pm);\n            if (sequence != null) {\n                name = sequence.toString();\n            }\n            icon = appInfo.loadIcon(pm);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public boolean isInstalling() {\n        return isInstalling;\n    }\n\n    @Override\n    public boolean isLoading() {\n        return isLoading;\n    }\n\n    @Override\n    public boolean isFirstOpen() {\n        return isFirstOpen;\n    }\n\n    @Override\n    public Drawable getIcon() {\n        return icon;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public boolean canReorder() {\n        return true;\n    }\n\n    @Override\n    public boolean canLaunch() {\n        return true;\n    }\n\n    @Override\n    public boolean canDelete() {\n        return true;\n    }\n\n    @Override\n    public boolean canCreateShortcut() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppDataSource.java",
    "content": "package io.virtualapp.home.repo;\n\nimport android.content.Context;\n\nimport com.lody.virtual.remote.InstallResult;\n\nimport org.jdeferred.Promise;\n\nimport java.io.File;\nimport java.util.List;\n\nimport io.virtualapp.home.models.AppData;\nimport io.virtualapp.home.models.AppInfo;\nimport io.virtualapp.home.models.AppInfoLite;\n\n/**\n * @author Lody\n * @version 1.0\n */\npublic interface AppDataSource {\n\n    /**\n     * @return All the Applications we Virtual.\n     */\n    Promise<List<AppData>, Throwable, Void> getVirtualApps();\n\n    /**\n     * @param context Context\n     * @return All the Applications we Installed.\n     */\n    Promise<List<AppInfo>, Throwable, Void> getInstalledApps(Context context);\n\n    Promise<List<AppInfo>, Throwable, Void> getStorageApps(Context context, File rootDir);\n\n    InstallResult addVirtualApp(AppInfoLite info);\n\n    boolean removeVirtualApp(String packageName, int userId);\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/repo/AppRepository.java",
    "content": "package io.virtualapp.home.repo;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport com.lody.virtual.GmsSupport;\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.DeviceUtil;\nimport com.lody.virtual.remote.InstallResult;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport org.jdeferred.Promise;\n\nimport java.io.File;\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.models.AppData;\nimport io.virtualapp.home.models.AppInfo;\nimport io.virtualapp.home.models.AppInfoLite;\nimport io.virtualapp.home.models.MultiplePackageAppData;\nimport io.virtualapp.home.models.PackageAppData;\nimport io.virtualapp.utils.HanziToPinyin;\n\n/**\n * @author Lody\n */\npublic class AppRepository implements AppDataSource {\n\n    private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);\n    private static final List<String> SCAN_PATH_LIST = Arrays.asList(\n            \".\",\n            \"wandoujia/app\",\n            \"tencent/tassistant/apk\",\n            \"BaiduAsa9103056\",\n            \"360Download\",\n            \"pp/downloader\",\n            \"pp/downloader/apk\",\n            \"pp/downloader/silent/apk\");\n\n    private static final int MAX_SCAN_DEPTH = 2;\n\n    private Context mContext;\n\n    public AppRepository(Context context) {\n        mContext = context;\n    }\n\n    private static boolean isSystemApplication(PackageInfo packageInfo) {\n        return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0\n                && !GmsSupport.isGmsFamilyPackage(packageInfo.packageName);\n    }\n\n    @Override\n    public Promise<List<AppData>, Throwable, Void> getVirtualApps() {\n        return VUiKit.defer().when(() -> {\n            List<InstalledAppInfo> infos = VirtualCore.get().getInstalledApps(0);\n            List<AppData> models = new ArrayList<>();\n            for (InstalledAppInfo info : infos) {\n                if (!VirtualCore.get().isPackageLaunchable(info.packageName)) {\n                    continue;\n                }\n                PackageAppData data = new PackageAppData(mContext, info);\n                if (VirtualCore.get().isAppInstalledAsUser(0, info.packageName)) {\n                    models.add(data);\n                }\n                int[] userIds = info.getInstalledUsers();\n                for (int userId : userIds) {\n                    if (userId != 0) {\n                        models.add(new MultiplePackageAppData(data, userId));\n                    }\n                }\n            }\n            return models;\n        });\n    }\n\n    @Override\n    public Promise<List<AppInfo>, Throwable, Void> getInstalledApps(Context context) {\n        return VUiKit.defer().when(() -> convertPackageInfoToAppData(context, context.getPackageManager().getInstalledPackages(PackageManager.GET_META_DATA), true));\n    }\n\n    @Override\n    public Promise<List<AppInfo>, Throwable, Void> getStorageApps(Context context, File rootDir) {\n        // return VUiKit.defer().when(() -> convertPackageInfoToAppData(context, findAndParseAPKs(context, rootDir, SCAN_PATH_LIST), false));\n        return VUiKit.defer().when(() -> convertPackageInfoToAppData(context, findAndParseApkRecursively(context, rootDir,null, 0), false));\n    }\n\n    private List<PackageInfo> findAndParseApkRecursively(Context context, File rootDir, List<PackageInfo> result, int depth) {\n        if (result == null) {\n            result = new ArrayList<>();\n        }\n\n        if (depth > MAX_SCAN_DEPTH) {\n            return result;\n        }\n\n        File[] dirFiles = rootDir.listFiles();\n\n        if (dirFiles == null) {\n            return Collections.emptyList();\n        }\n\n        for (File f: dirFiles) {\n            if (f.isDirectory()) {\n                List<PackageInfo> andParseApkRecursively = findAndParseApkRecursively(context, f, new ArrayList<>(), depth + 1);\n                result.addAll(andParseApkRecursively);\n            }\n\n            if (!(f.isFile() && f.getName().toLowerCase().endsWith(\".apk\"))) {\n                continue;\n            }\n\n            PackageInfo pkgInfo = null;\n            try {\n                pkgInfo = context.getPackageManager().getPackageArchiveInfo(f.getAbsolutePath(), PackageManager.GET_META_DATA);\n                pkgInfo.applicationInfo.sourceDir = f.getAbsolutePath();\n                pkgInfo.applicationInfo.publicSourceDir = f.getAbsolutePath();\n            } catch (Exception e) {\n                // Ignore\n            }\n            if (pkgInfo != null) {\n                result.add(pkgInfo);\n            }\n        }\n        return result;\n    }\n\n    private List<PackageInfo> findAndParseAPKs(Context context, File rootDir, List<String> paths) {\n        List<PackageInfo> packageList = new ArrayList<>();\n        if (paths == null)\n            return packageList;\n        for (String path : paths) {\n            File[] dirFiles = new File(rootDir, path).listFiles();\n            if (dirFiles == null)\n                continue;\n            for (File f : dirFiles) {\n                if (!f.getName().toLowerCase().endsWith(\".apk\"))\n                    continue;\n                PackageInfo pkgInfo = null;\n                try {\n                    pkgInfo = context.getPackageManager().getPackageArchiveInfo(f.getAbsolutePath(), 0);\n                    pkgInfo.applicationInfo.sourceDir = f.getAbsolutePath();\n                    pkgInfo.applicationInfo.publicSourceDir = f.getAbsolutePath();\n                } catch (Exception e) {\n                    // Ignore\n                }\n                if (pkgInfo != null)\n                    packageList.add(pkgInfo);\n            }\n        }\n        return packageList;\n    }\n\n    private List<AppInfo> convertPackageInfoToAppData(Context context, List<PackageInfo> pkgList, boolean fastOpen) {\n        PackageManager pm = context.getPackageManager();\n        List<AppInfo> list = new ArrayList<>(pkgList.size());\n        String hostPkg = VirtualCore.get().getHostPkg();\n        for (PackageInfo pkg : pkgList) {\n            // ignore the host package\n            if (hostPkg.equals(pkg.packageName)) {\n                continue;\n            }\n\n            // ignore taichi package\n            if (VirtualCore.TAICHI_PACKAGE.equals(pkg.packageName)) {\n                continue;\n            }\n\n            // ignore the System package\n            if (isSystemApplication(pkg)) {\n                continue;\n            }\n            ApplicationInfo ai = pkg.applicationInfo;\n            String path = ai.publicSourceDir != null ? ai.publicSourceDir : ai.sourceDir;\n            boolean splitApk = false;\n            if (ai.splitPublicSourceDirs != null || ai.splitSourceDirs != null) {\n                splitApk = true;\n                path = new File(path).getParent();\n            }\n\n            if (path == null) {\n                continue;\n            }\n            AppInfo info = new AppInfo();\n            info.packageName = pkg.packageName;\n            info.fastOpen = fastOpen;\n            info.path = path;\n            info.icon = null;  // Use Glide to load the icon async\n            info.name = ai.loadLabel(pm);\n            info.version = pkg.versionName;\n            info.splitApk = splitApk;\n            InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg.packageName, 0);\n            if (installedAppInfo != null) {\n                info.cloneCount = installedAppInfo.getInstalledUsers().length;\n            }\n            if (ai.metaData != null && ai.metaData.containsKey(\"xposedmodule\")) {\n                info.disableMultiVersion = true;\n                info.cloneCount = 0;\n            }\n            list.add(info);\n        }\n        // sort by name\n        Collections.sort(list, (o1, o2) -> {\n            HanziToPinyin hanziToPinyin = HanziToPinyin.getInstance();\n            String pinyin1 = hanziToPinyin.toPinyinString(o1.name.toString().trim());\n            String pinyin2 = hanziToPinyin.toPinyinString(o2.name.toString().trim());\n            return pinyin1.compareTo(pinyin2);\n        });\n        return list;\n    }\n\n    @Override\n    public InstallResult addVirtualApp(AppInfoLite info) {\n        int flags = InstallStrategy.COMPARE_VERSION | InstallStrategy.SKIP_DEX_OPT;\n        info.fastOpen = false; // disable fast open for compile.\n        if (DeviceUtil.isMeizuBelowN()) {\n            info.fastOpen = true;\n        }\n        if (info.fastOpen) {\n            flags |= InstallStrategy.DEPEND_SYSTEM_IF_EXIST;\n        }\n        if (info.disableMultiVersion) {\n            flags |= InstallStrategy.UPDATE_IF_EXIST;\n        }\n        return VirtualCore.get().installPackage(info.path, flags);\n    }\n\n    @Override\n    public boolean removeVirtualApp(String packageName, int userId) {\n        return VirtualCore.get().uninstallPackageAsUser(packageName, userId);\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/home/repo/PackageAppDataStorage.java",
    "content": "package io.virtualapp.home.repo;\n\nimport android.content.pm.ApplicationInfo;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.virtualapp.XApp;\nimport io.virtualapp.abs.Callback;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.models.PackageAppData;\n\n/**\n * @author Lody\n *         <p>\n *         Cache the loaded PackageAppData.\n */\npublic class PackageAppDataStorage {\n\n    private static final PackageAppDataStorage STORAGE = new PackageAppDataStorage();\n    private final Map<String, PackageAppData> packageDataMap = new HashMap<>();\n\n    public static PackageAppDataStorage get() {\n        return STORAGE;\n    }\n\n    public PackageAppData acquire(String packageName) {\n        PackageAppData data;\n        synchronized (packageDataMap) {\n            data = packageDataMap.get(packageName);\n            if (data == null) {\n                data = loadAppData(packageName);\n            }\n        }\n        return data;\n    }\n\n    public void acquire(String packageName, Callback<PackageAppData> callback) {\n        VUiKit.defer()\n                .when(() -> acquire(packageName))\n                .done(callback::callback);\n    }\n\n    private PackageAppData loadAppData(String packageName) {\n        InstalledAppInfo setting = VirtualCore.get().getInstalledAppInfo(packageName, 0);\n        if (setting != null) {\n            PackageAppData data = new PackageAppData(XApp.getApp(), setting);\n            synchronized (packageDataMap) {\n                packageDataMap.put(packageName, data);\n            }\n            return data;\n        }\n        return null;\n    }\n\n    public PackageAppData acquire(ApplicationInfo appInfo) {\n        PackageAppData data;\n        synchronized (packageDataMap) {\n            data = packageDataMap.get(appInfo.packageName);\n            if (data == null) {\n                data = loadAppData(appInfo);\n            }\n        }\n        return data;\n    }\n\n    public void acquire(ApplicationInfo appInfo, Callback<PackageAppData> callback) {\n        VUiKit.defer()\n                .when(() -> acquire(appInfo))\n                .done(callback::callback);\n    }\n\n    private PackageAppData loadAppData(ApplicationInfo appInfo) {\n        PackageAppData data = new PackageAppData(XApp.getApp(), appInfo);\n        synchronized (packageDataMap) {\n            packageDataMap.put(appInfo.packageName, data);\n        }\n        return data;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/AboutActivity.java",
    "content": "package io.virtualapp.settings;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AlertDialog;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport java.util.Calendar;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.update.VAVersionService;\nimport mehdi.sakout.aboutpage.AboutPage;\nimport mehdi.sakout.aboutpage.Element;\n\n/**\n * author: weishu on 18/1/12.\n */\npublic class AboutActivity extends VActivity {\n\n    private AboutPage mPage;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        mPage = new AboutPage(this)\n                .isRTL(false)\n                .setImage(R.mipmap.ic_launcher)\n                .addItem(getCopyRightsElement())\n                .addItem(getVersionElement())\n                .addItem(getCheckUpdateElement())\n                .addItem(getFeedbackEmailElement())\n                .addItem(getThanksElement())\n                .addItem(getFeedbacTelegramElement())\n                .addItem(getWebsiteElement())\n                .addGitHub(\"tiann\");\n\n        View aboutPage = mPage.create();\n\n        setContentView(aboutPage);\n    }\n\n    Element getCopyRightsElement() {\n        Element copyRightsElement = new Element();\n        final String copyrights = String.format(getString(R.string.copy_right), Calendar.getInstance().get(Calendar.YEAR));\n        copyRightsElement.setTitle(copyrights);\n        copyRightsElement.setGravity(Gravity.START);\n        return copyRightsElement;\n    }\n\n    Element getVersionElement() {\n        Element version = new Element();\n        String versionName = \"unknown\";\n        try {\n            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);\n            versionName = packageInfo.versionName;\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        version.setTitle(getResources().getString(R.string.about_version_title, versionName));\n\n        final int[] clickCount = {0};\n        version.setOnClickListener(v -> {\n            clickCount[0]++;\n            if (clickCount[0] == 3) {\n                mPage.addItem(getFeedbackQQElement());\n                mPage.addItem(getFeedbackWechatElement());\n            }\n        });\n        return version;\n    }\n\n    Element getFeedbackQQElement() {\n        Element feedback = new Element();\n        final String qqGroup = \"597478474\";\n        feedback.setTitle(getResources().getString(R.string.about_feedback_qq_title));\n\n        feedback.setOnClickListener(v -> {\n            ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);\n            if (clipboardManager != null) {\n                clipboardManager.setPrimaryClip(ClipData.newPlainText(null, qqGroup));\n            }\n            Toast.makeText(v.getContext(), getResources().getString(R.string.about_feedback_tips), Toast.LENGTH_SHORT).show();\n        });\n        return feedback;\n    }\n\n    Element getFeedbackEmailElement() {\n        Element emailElement = new Element();\n        final String email = \"virtualxposed@gmail.com\";\n        String title = getResources().getString(R.string.about_feedback_title);\n        emailElement.setTitle(title);\n\n        Uri uri = Uri.parse(\"mailto:\" + email);\n        Intent intent = new Intent(Intent.ACTION_SENDTO, uri);\n        intent.putExtra(Intent.EXTRA_SUBJECT, title); // 主题\n\n        String hint = getResources().getString(R.string.about_feedback_hint);\n        intent.putExtra(Intent.EXTRA_TEXT, hint);\n        emailElement.setIntent(intent);\n        return emailElement;\n    }\n\n    Element getFeedbackWechatElement() {\n        Element feedback = new Element();\n        // final String weChatGroup = \"CSYJZF\";\n        feedback.setTitle(getResources().getString(R.string.about_feedback_wechat_title));\n\n        feedback.setOnClickListener(v -> {\n            ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);\n            if (clipboardManager != null) {\n                clipboardManager.setPrimaryClip(ClipData.newPlainText(null, \"VirtualXposed\"));\n            }\n            Toast.makeText(v.getContext(), getResources().getString(R.string.about_feedback_tips), Toast.LENGTH_SHORT).show();\n        });\n        return feedback;\n    }\n\n    Element getFeedbacTelegramElement() {\n        Element feedback = new Element();\n        final String weChatGroup = \"VirtualXposed\";\n        feedback.setTitle(getResources().getString(R.string.about_feedback_tel_title, weChatGroup));\n\n        feedback.setOnClickListener(v -> {\n            Intent intent = new Intent(Intent.ACTION_VIEW);\n            intent.setData(Uri.parse(\"https://t.me/joinchat/Gtti8Usj1JD4TchHQmy-ew\"));\n            try {\n                startActivity(intent);\n            } catch (Throwable ignored) {\n            }\n        });\n        return feedback;\n    }\n\n    Element getWebsiteElement() {\n        Element feedback = new Element();\n        feedback.setTitle(getResources().getString(R.string.about_website_title));\n\n        feedback.setOnClickListener(v -> {\n            Intent intent = new Intent(Intent.ACTION_VIEW);\n            intent.setData(Uri.parse(\"http://vxposed.com\"));\n            try {\n                startActivity(intent);\n            } catch (Throwable ignored) {\n            }\n        });\n        return feedback;\n    }\n\n    Element getThanksElement() {\n        Element thanks = new Element();\n        thanks.setTitle(getResources().getString(R.string.about_thanks));\n        thanks.setOnClickListener(v -> {\n            AlertDialog alertDialog = new AlertDialog.Builder(this, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                    .setTitle(R.string.thanks_dialog_title)\n                    .setMessage(R.string.thanks_dialog_content)\n                    .setPositiveButton(R.string.about_icon_yes, null)\n                    .create();\n            try {\n                alertDialog.show();\n            } catch (Throwable ignored) {\n                // BadTokenException.\n            }\n        });\n        return thanks;\n    }\n\n    Element getCheckUpdateElement() {\n        Element checkUpdate = new Element();\n        checkUpdate.setTitle(getResources().getString(R.string.check_update));\n        checkUpdate.setOnClickListener(v -> {\n            VAVersionService.checkUpdateImmediately(getApplicationContext(), true);\n        });\n        return checkUpdate;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/AppManageActivity.java",
    "content": "package io.virtualapp.settings;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.Settings;\nimport android.support.annotation.Nullable;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.PopupMenu;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VirtualStorageManager;\nimport com.lody.virtual.helper.ArtDexOptimizer;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.glide.GlideUtils;\n\n/**\n * @author weishu\n * @date 18/2/15.\n */\n\npublic class AppManageActivity extends VActivity {\n\n    private ListView mListView;\n    private List<AppManageInfo> mInstalledApps = new ArrayList<>();\n    private AppManageAdapter mAdapter;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_list);\n        mListView = (ListView) findViewById(R.id.list);\n        mAdapter = new AppManageAdapter();\n        mListView.setAdapter(mAdapter);\n\n        mListView.setOnItemClickListener((parent, view, position, id) -> {\n            AppManageInfo appManageInfo = mInstalledApps.get(position);\n            showContextMenu(appManageInfo, view);\n        });\n        loadAsync();\n    }\n\n    private void loadAsync() {\n        VUiKit.defer().when(this::loadApp).done((v) -> mAdapter.notifyDataSetChanged());\n    }\n\n    private void loadApp() {\n\n        List<AppManageInfo> ret = new ArrayList<>();\n        List<InstalledAppInfo> installedApps = VirtualCore.get().getInstalledApps(0);\n        PackageManager packageManager = getPackageManager();\n        for (InstalledAppInfo installedApp : installedApps) {\n            int[] installedUsers = installedApp.getInstalledUsers();\n            for (int installedUser : installedUsers) {\n                AppManageInfo info = new AppManageInfo();\n                info.userId = installedUser;\n                ApplicationInfo applicationInfo = installedApp.getApplicationInfo(installedUser);\n                info.name = applicationInfo.loadLabel(packageManager);\n//                info.icon = applicationInfo.loadIcon(packageManager);  //Use Glide to load icon async\n                info.pkgName = installedApp.packageName;\n                info.path = applicationInfo.sourceDir;\n                ret.add(info);\n            }\n        }\n        mInstalledApps.clear();\n        mInstalledApps.addAll(ret);\n    }\n\n    class AppManageAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            return mInstalledApps.size();\n        }\n\n        @Override\n        public AppManageInfo getItem(int position) {\n            return mInstalledApps.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ViewHolder holder;\n            if (convertView == null) {\n                holder = new ViewHolder(AppManageActivity.this, parent);\n                convertView = holder.root;\n                convertView.setTag(holder);\n            } else {\n                holder = (ViewHolder) convertView.getTag();\n            }\n\n            AppManageInfo item = getItem(position);\n\n            holder.label.setText(item.getName());\n\n            if (VirtualCore.get().isOutsideInstalled(item.pkgName)) {\n                GlideUtils.loadInstalledPackageIcon(getContext(), item.pkgName, holder.icon, android.R.drawable.sym_def_app_icon);\n            } else {\n                GlideUtils.loadPackageIconFromApkFile(getContext(), item.path, holder.icon, android.R.drawable.sym_def_app_icon);\n            }\n\n            holder.button.setOnClickListener(v -> showContextMenu(item, v));\n\n            return convertView;\n        }\n    }\n\n    private void showContextMenu(AppManageInfo appManageInfo, View anchor) {\n        if (appManageInfo == null) {\n            return;\n        }\n        PopupMenu popupMenu = new PopupMenu(this, anchor);\n        popupMenu.inflate(R.menu.app_manage_menu);\n        MenuItem redirectMenu = popupMenu.getMenu().findItem(R.id.action_redirect);\n\n        try {\n            final String packageName = appManageInfo.pkgName;\n            final int userId = appManageInfo.userId;\n            boolean virtualStorageEnable = VirtualStorageManager.get().isVirtualStorageEnable(packageName, userId);\n            redirectMenu.setTitle(virtualStorageEnable ? R.string.app_manage_redirect_off : R.string.app_manage_redirect_on);\n        } catch (Throwable e) {\n            redirectMenu.setVisible(false);\n        }\n\n        popupMenu.setOnMenuItemClickListener(item -> {\n            switch (item.getItemId()) {\n                case R.id.action_uninstall:\n                    showUninstallDialog(appManageInfo, appManageInfo.getName());\n                    break;\n                case R.id.action_repair:\n                    showRepairDialog(appManageInfo);\n                    break;\n                case R.id.action_redirect:\n                    showStorageRedirectDialog(appManageInfo);\n                    break;\n            }\n            return false;\n        });\n        try {\n            popupMenu.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    private void showRepairDialog(AppManageInfo item) {\n        ProgressDialog dialog = new ProgressDialog(this);\n        dialog.setTitle(getResources().getString(R.string.app_manage_repairing));\n        try {\n            dialog.setCancelable(false);\n            dialog.show();\n        } catch (Throwable e) {\n            return;\n        }\n\n        VUiKit.defer().when(() -> {\n            NougatPolicy.fullCompile(getApplicationContext());\n\n            String packageName = item.pkgName;\n            String apkPath = item.path;\n\n            if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(apkPath)) {\n                return;\n            }\n\n            // 1. kill package\n            VirtualCore.get().killApp(packageName, item.userId);\n\n            // 2. backup the odex file\n            File odexFile = VEnvironment.getOdexFile(packageName);\n            if (odexFile.delete()) {\n                try {\n                    ArtDexOptimizer.compileDex2Oat(apkPath, odexFile.getPath());\n                } catch (IOException e) {\n                    throw new RuntimeException(\"compile failed.\");\n                }\n            }\n        }).done((v) -> {\n            dismiss(dialog);\n            showAppDetailDialog();\n        }).fail((v) -> {\n            dismiss(dialog);\n            Toast.makeText(this, R.string.app_manage_repair_failed_tips, Toast.LENGTH_SHORT).show();\n        });\n    }\n\n    private void showAppDetailDialog() {\n        AlertDialog alertDialog = new AlertDialog.Builder(AppManageActivity.this)\n                .setTitle(R.string.app_manage_repair_success_title)\n                .setMessage(getResources().getString(R.string.app_manage_repair_success_content))\n                .setPositiveButton(R.string.app_manage_repair_reboot_now, (dialog, which) -> {\n                    String packageName = getPackageName();\n                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,\n                            Uri.fromParts(\"package\", packageName, null));\n                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);\n                    startActivity(intent);\n                })\n                .create();\n\n        alertDialog.setCancelable(false);\n\n        try {\n            alertDialog.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    private void showUninstallDialog(AppManageInfo item, CharSequence name) {\n        AlertDialog alertDialog = new AlertDialog.Builder(AppManageActivity.this)\n                .setTitle(com.android.launcher3.R.string.home_menu_delete_title)\n                .setMessage(getResources().getString(com.android.launcher3.R.string.home_menu_delete_content, name))\n                .setPositiveButton(android.R.string.yes, (dialog, which) -> {\n                    VirtualCore.get().uninstallPackageAsUser(item.pkgName, item.userId);\n                    loadAsync();\n                })\n                .setNegativeButton(android.R.string.no, null)\n                .create();\n        try {\n            alertDialog.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    private void showStorageRedirectDialog(AppManageInfo item) {\n        final String packageName = item.pkgName;\n        final int userId = item.userId;\n        boolean virtualStorageEnable;\n        try {\n            virtualStorageEnable = VirtualStorageManager.get().isVirtualStorageEnable(packageName, userId);\n        } catch (Throwable e) {\n            return;\n        }\n\n        AlertDialog alertDialog = new AlertDialog.Builder(AppManageActivity.this)\n                .setTitle(virtualStorageEnable ? R.string.app_manage_redirect_off : R.string.app_manage_redirect_on)\n                .setMessage(getResources().getString(R.string.app_manage_redirect_desc))\n                .setPositiveButton(virtualStorageEnable ? R.string.app_manage_redirect_off_confirm : R.string.app_manage_redirect_on_confirm,\n                        (dialog, which) -> {\n                            try {\n                                VirtualStorageManager.get().setVirtualStorageState(packageName, userId, !virtualStorageEnable);\n                            } catch (Throwable ignored) {\n                            }\n                        })\n                .setNegativeButton(android.R.string.no, null)\n                .create();\n        try {\n            alertDialog.show();\n        } catch (Throwable ignored) {\n        }\n    }\n\n    static class ViewHolder {\n        ImageView icon;\n        TextView label;\n        ImageView button;\n\n        View root;\n\n        ViewHolder(Context context, ViewGroup parent) {\n            root = LayoutInflater.from(context).inflate(R.layout.item_app_manage, parent, false);\n            icon = root.findViewById(R.id.item_app_icon);\n            label = root.findViewById(R.id.item_app_name);\n            button = root.findViewById(R.id.item_app_button);\n        }\n    }\n\n    static class AppManageInfo {\n        CharSequence name;\n        int userId;\n        Drawable icon;\n        String pkgName;\n        String path;\n\n        CharSequence getName() {\n            if (userId == 0) {\n                return name;\n            } else {\n                return name + \"[\" + (userId + 1) + \"]\";\n            }\n        }\n    }\n\n    private static void dismiss(Dialog dialog) {\n        if (dialog == null) {\n            return;\n        }\n        try {\n            dialog.dismiss();\n        } catch (Throwable ignored) {\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/NougatPolicy.java",
    "content": "package io.virtualapp.settings;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport java.lang.reflect.Method;\n\n/**\n * Android 7.0 全量编译策略\n * Created by weishu on 17/6/12.\n */\n\npublic class NougatPolicy {\n\n    static boolean fullCompile(Context context) {\n        if (Build.VERSION.SDK_INT < 24) {\n            return true;\n        }\n        try {\n            Object pm = getPackageManagerBinderProxy();\n            if (pm == null) {\n                return false;\n            }\n            /*\n            @Override\n            public boolean performDexOptMode(String packageName,\n            boolean checkProfiles, String targetCompilerFilter, boolean force) {\n                int dexOptStatus = performDexOptTraced(packageName, checkProfiles,\n                        targetCompilerFilter, force);\n                return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;\n            */\n\n            final Method performDexOptMode = pm.getClass().getDeclaredMethod(\"performDexOptMode\",\n                    String.class, boolean.class, String.class, boolean.class);\n            return (boolean) performDexOptMode.invoke(pm, context.getPackageName(), false, \"speed\", true);\n        } catch (Throwable e) {\n            return false;\n        }\n    }\n\n    public static boolean clearCompileData(Context context) {\n        boolean ret;\n        try {\n            Object pm = getPackageManagerBinderProxy();\n            final Method performDexOpt = pm.getClass().getDeclaredMethod(\"performDexOpt\", String.class,\n                    boolean.class, int.class, boolean.class);\n            ret = (Boolean) performDexOpt.invoke(pm, context.getPackageName(), false, 2 /*install*/, true);\n        } catch (Throwable e) {\n            ret = false;\n        }\n        return ret;\n    }\n\n    private static Object getPackageManagerBinderProxy() throws Exception {\n        Class<?> activityThread = Class.forName(\"android.app.ActivityThread\");\n        final Method getPackageManager = activityThread.getDeclaredMethod(\"getPackageManager\");\n        return getPackageManager.invoke(null);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/OnlinePlugin.java",
    "content": "package io.virtualapp.settings;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.os.SystemClock;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.remote.InstallResult;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport io.virtualapp.R;\nimport io.virtualapp.gms.FakeGms;\nimport io.virtualapp.home.LoadingActivity;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\nimport static io.virtualapp.utils.DialogUtil.showDialog;\n\n/**\n * @author weishu\n * @date 2018/7/5.\n */\npublic class OnlinePlugin {\n\n    private static final String TAG = \"OnlinePlugin\";\n\n    public static final String FILE_MANAGE_PACKAGE = \"com.amaze.filemanager\";\n    public static final String FILE_MANAGE_URL = \"http://vaexposed.weishu.me/amaze.json\";\n\n    public static final String PERMISSION_MANAGE_PACKAGE = \"eu.faircode.xlua\";\n    public static final String PERMISSION_MANAGE_URL = \"http://vaexposed.weishu.me/xlua.json\";\n\n    public static void openOrDownload(Activity context, String packageName, String url, String tips) {\n        if (context == null || packageName == null) {\n            return;\n        }\n\n        if (VirtualCore.get().isAppInstalled(packageName)) {\n            LoadingActivity.launch(context, packageName, 0);\n            return;\n        }\n\n        AlertDialog failDialog = new AlertDialog.Builder(context, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                .setTitle(android.R.string.dialog_alert_title)\n                .setMessage(tips)\n                .setPositiveButton(android.R.string.ok, ((dialog1, which1) -> {\n                    ProgressDialog progressDialog = new ProgressDialog(context);\n                    progressDialog.setCancelable(false);\n                    progressDialog.show();\n\n                    Executors.newSingleThreadExecutor().submit(() -> {\n                        String error = downloadAndInstall(context, progressDialog, url, packageName);\n                        try {\n                            progressDialog.dismiss();\n                        } catch (Throwable e) {\n                            e.printStackTrace();\n                        }\n\n                        if (error == null) {\n                            context.runOnUiThread(() -> {\n                                LoadingActivity.launch(context, packageName, 0);\n                            });\n                        } else {\n                            context.runOnUiThread(() -> Toast.makeText(context, error, Toast.LENGTH_SHORT).show());\n                        }\n\n                    });\n\n                }))\n                .setNegativeButton(android.R.string.cancel, null)\n                .create();\n\n        showDialog(failDialog);\n    }\n\n    private static String downloadAndInstall(Activity activity, ProgressDialog dialog, String url, String packageName) {\n        OkHttpClient client = new OkHttpClient.Builder()\n                .connectTimeout(30, TimeUnit.SECONDS)\n                .readTimeout(30, TimeUnit.SECONDS)\n                .writeTimeout(30, TimeUnit.SECONDS)\n                .build();\n\n        Request request = new Request.Builder()\n                .url(url)\n                .build();\n\n        updateMessage(activity, dialog, \"Prepare download...\");\n        Response response;\n        try {\n            response = client.newCall(request).execute();\n        } catch (IOException e) {\n            return \"Download failed, please check your network, error: 0\";\n        }\n\n        if (!response.isSuccessful()) {\n            return \"Download failed, please check your network, error: 1\";\n        }\n\n        Log.i(TAG, \"response success: \" + response.code());\n        if (200 != response.code()) {\n            return \"Download failed, please check your network, error: 2\";\n        }\n\n        updateMessage(activity, dialog, \"Parsing config...\");\n        ResponseBody body = response.body();\n        if (body == null) {\n            return \"Download failed, please check your network, error: 3\";\n        }\n\n        String string;\n        try {\n            string = body.string();\n        } catch (IOException e) {\n            return \"Download failed, please check your network, error: 4\";\n        }\n\n        JSONObject jsonObject;\n        try {\n            jsonObject = new JSONObject(string);\n        } catch (JSONException e) {\n            return \"Download failed, please check your network, error: 5\";\n        }\n        String downloadLink;\n        boolean isXposed;\n        try {\n            downloadLink = jsonObject.getString(\"url\");\n            isXposed = jsonObject.optBoolean(\"xposed\", false);\n        } catch (JSONException e) {\n            return \"Download failed, please check your network, error: 6\";\n        }\n\n        File outFile = new File(activity.getCacheDir(), packageName + \".apk\");\n        FakeGms.downloadFile(downloadLink, outFile, progress -> updateMessage(activity, dialog, \"download \" + packageName + \"...\" + progress + \"%\"));\n\n        updateMessage(activity, dialog, \"installing \" + packageName);\n\n        InstallResult installResult = VirtualCore.get().installPackage(outFile.getAbsolutePath(), InstallStrategy.UPDATE_IF_EXIST);\n        if (!installResult.isSuccess) {\n            return \"install \" + packageName + \" failed: \" + installResult.error;\n        }\n\n        if (isXposed) {\n            // Enable the Xposed module.\n            updateMessage(activity, dialog, \"enable \" + packageName + \" in Xposed Installer\");\n\n            File dataDir = VEnvironment.getDataUserPackageDirectory(0, \"de.robv.android.xposed.installer\");\n            File modulePath = VEnvironment.getPackageResourcePath(packageName);\n            File configDir = new File(dataDir, \"exposed_conf\" + File.separator + \"modules.list\");\n            FileWriter writer = null;\n            try {\n                writer = new FileWriter(configDir, true);\n                writer.append(modulePath.getAbsolutePath());\n                writer.flush();\n\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                if (writer != null) {\n                    try {\n                        writer.close();\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }\n\n        updateMessage(activity, dialog, \" install success!!\");\n        SystemClock.sleep(300);\n\n        return null;\n    }\n\n    private static void updateMessage(Activity activity, ProgressDialog dialog, String msg) {\n        if (activity == null || dialog == null || TextUtils.isEmpty(msg)) {\n            return;\n        }\n        Log.i(TAG, \"update dialog message: \" + msg);\n        activity.runOnUiThread(() -> {\n            dialog.setMessage(msg);\n        });\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/RecommendPluginActivity.java",
    "content": "package io.virtualapp.settings;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VActivity;\n\n/**\n * author: weishu on 2018/5/9.\n */\n\npublic class RecommendPluginActivity extends VActivity {\n\n    private List<PluginInfo> mData = new ArrayList<>();\n    private PluginAdapter mAdapter;\n    private ProgressDialog mLoadingDialog;\n\n    private static final String ADDRESS = \"http://vaexposed.weishu.me/plugin.json\";\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_list);\n        mLoadingDialog = new ProgressDialog(this);\n        mLoadingDialog.setTitle(\"Loading\");\n\n        ListView mListView = findViewById(R.id.list);\n        mAdapter = new PluginAdapter();\n        mListView.setAdapter(mAdapter);\n        mListView.setEmptyView(findViewById(R.id.empty_view));\n\n        mListView.setOnItemClickListener((parent, view, position, id) -> {\n            try {\n                PluginInfo item = mAdapter.getItem(position);\n                Intent intent = new Intent(Intent.ACTION_VIEW);\n                intent.setData(Uri.parse(item.link));\n                startActivity(intent);\n            } catch (Throwable ignored) {\n                ignored.printStackTrace();\n            }\n        });\n\n        loadRecommend();\n    }\n\n    private void loadRecommend() {\n        try {\n            mLoadingDialog.show();\n        } catch (Throwable ignored) {\n        }\n\n        defer().when(() -> {\n            JSONArray jsonArray = null;\n\n            URL url = new URL(ADDRESS);\n            HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n            connection.setRequestMethod(\"GET\");\n            connection.setConnectTimeout(30000);\n            connection.setReadTimeout(30000);\n            if(connection.getResponseCode() == 200){\n                BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), \"utf-8\"));\n                String line;\n                StringBuilder sb = new StringBuilder();\n                while ((line = br.readLine()) != null) {\n                    sb.append(line);\n                }\n                jsonArray = new JSONArray(sb.toString());\n                br.close();\n            }\n\n            connection.disconnect();\n            return jsonArray;\n        }).done(jsonArray -> {\n            mLoadingDialog.dismiss();\n\n            if (jsonArray == null) {\n                return;\n            }\n            mData.clear();\n\n            int length = jsonArray.length();\n            for (int i = 0; i < length; i++) {\n                PluginInfo info = new PluginInfo();\n                try {\n                    JSONObject jsonObject = jsonArray.getJSONObject(i);\n                    info.name = jsonObject.getString(\"name\");\n                    info.desc = jsonObject.getString(\"desc\");\n                    info.link = jsonObject.getString(\"link\");\n                } catch (JSONException e) {\n                    continue;\n                }\n                mData.add(info);\n            }\n\n            mAdapter.notifyDataSetChanged();\n        }).fail((v) -> {\n            mLoadingDialog.dismiss();\n        });\n    }\n\n    static class PluginInfo {\n        String name;\n        String desc;\n        String link;\n    }\n\n    static class ViewHolder {\n        TextView title;\n        TextView summary;\n\n        View root;\n\n        public ViewHolder(Context context, ViewGroup parent) {\n            root = LayoutInflater.from(context).inflate(R.layout.item_plugin_recommend, parent, false);\n            title = root.findViewById(R.id.item_plugin_name);\n            summary = root.findViewById(R.id.item_plugin_summary);\n        }\n    }\n\n    class PluginAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            return mData.size();\n        }\n\n        @Override\n        public PluginInfo getItem(int position) {\n            return mData.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ViewHolder holder;\n            if (convertView == null) {\n                holder = new ViewHolder(RecommendPluginActivity.this, parent);\n                convertView = holder.root;\n                convertView.setTag(holder);\n            } else {\n                holder = (ViewHolder) convertView.getTag();\n            }\n\n            PluginInfo info = getItem(position);\n            holder.title.setText(info.name);\n            holder.summary.setText(info.desc);\n\n            return convertView;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/SettingsActivity.java",
    "content": "package io.virtualapp.settings;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.Preference;\nimport android.preference.PreferenceFragment;\nimport android.preference.PreferenceScreen;\nimport android.preference.SwitchPreference;\nimport android.widget.Toast;\n\nimport com.android.launcher3.LauncherFiles;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.ipc.VActivityManager;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport io.virtualapp.R;\nimport io.virtualapp.VCommends;\nimport io.virtualapp.gms.FakeGms;\nimport io.virtualapp.home.ListAppActivity;\nimport io.virtualapp.utils.Misc;\n\n/**\n * Settings activity for Launcher. Currently implements the following setting: Allow rotation\n */\npublic class SettingsActivity extends Activity {\n\n    private static final String ADVANCE_SETTINGS_KEY = \"settings_advance\";\n    private static final String ADD_APP_KEY = \"settings_add_app\";\n    private static final String MODULE_MANAGE_KEY = \"settings_module_manage\";\n    private static final String APP_MANAGE_KEY = \"settings_app_manage\";\n    private static final String TASK_MANAGE_KEY = \"settings_task_manage\";\n    private static final String DESKTOP_SETTINGS_KEY = \"settings_desktop\";\n    private static final String FAQ_SETTINGS_KEY = \"settings_faq\";\n    private static final String DONATE_KEY = \"settings_donate\";\n    private static final String ABOUT_KEY = \"settings_about\";\n    private static final String REBOOT_KEY = \"settings_reboot\";\n    private static final String HIDE_SETTINGS_KEY = \"advance_settings_hide_settings\";\n    private static final String DISABLE_INSTALLER_KEY = \"advance_settings_disable_installer\";\n    public static final String ENABLE_LAUNCHER = \"advance_settings_enable_launcher\";\n    private static final String INSTALL_GMS_KEY = \"advance_settings_install_gms\";\n    public static final String DIRECTLY_BACK_KEY = \"advance_settings_directly_back\";\n    private static final String RECOMMEND_PLUGIN = \"settings_plugin_recommend\";\n    private static final String DISABLE_RESIDENT_NOTIFICATION = \"advance_settings_disable_resident_notification\";\n    private static final String ALLOW_FAKE_SIGNATURE = \"advance_settings_allow_fake_signature\";\n    private static final String DISABLE_XPOSED = \"advance_settings_disable_xposed\";\n    private static final String FILE_MANAGE = \"settings_file_manage\";\n    private static final String PERMISSION_MANAGE = \"settings_permission_manage\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        if (savedInstanceState == null) {\n            // Display the fragment as the main content.\n            getFragmentManager().beginTransaction()\n                    .replace(android.R.id.content, new SettingsFragment())\n                    .commit();\n        }\n    }\n\n    /**\n     * This fragment shows the launcher preferences.\n     */\n    public static class SettingsFragment extends PreferenceFragment {\n\n\n        @Override\n        public void onCreate(Bundle savedInstanceState) {\n            super.onCreate(savedInstanceState);\n            getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);\n            addPreferencesFromResource(R.xml.settings_preferences);\n\n            // Setup allow rotation preference\n\n            Preference addApp = findPreference(ADD_APP_KEY);\n            Preference moduleManage = findPreference(MODULE_MANAGE_KEY);\n            Preference recommend = findPreference(RECOMMEND_PLUGIN);\n            Preference appManage = findPreference(APP_MANAGE_KEY);\n            Preference taskManage = findPreference(TASK_MANAGE_KEY);\n            Preference desktop = findPreference(DESKTOP_SETTINGS_KEY);\n            Preference faq = findPreference(FAQ_SETTINGS_KEY);\n            Preference donate = findPreference(DONATE_KEY);\n            Preference about = findPreference(ABOUT_KEY);\n            Preference reboot = findPreference(REBOOT_KEY);\n            Preference fileMange = findPreference(FILE_MANAGE);\n            Preference permissionManage = findPreference(PERMISSION_MANAGE);\n\n\n            SwitchPreference disableInstaller = (SwitchPreference) findPreference(DISABLE_INSTALLER_KEY);\n            SwitchPreference enableLauncher = (SwitchPreference) findPreference(ENABLE_LAUNCHER);\n            SwitchPreference disableResidentNotification = (SwitchPreference) findPreference(DISABLE_RESIDENT_NOTIFICATION);\n            SwitchPreference allowFakeSignature = (SwitchPreference) findPreference(ALLOW_FAKE_SIGNATURE);\n            SwitchPreference disableXposed = (SwitchPreference) findPreference(DISABLE_XPOSED);\n\n            addApp.setOnPreferenceClickListener(preference -> {\n                ListAppActivity.gotoListApp(getActivity());\n                return false;\n            });\n\n            moduleManage.setOnPreferenceClickListener(preference -> {\n                try {\n                    Intent t = new Intent();\n                    t.setComponent(new ComponentName(\"de.robv.android.xposed.installer\", \"de.robv.android.xposed.installer.WelcomeActivity\"));\n                    t.putExtra(\"fragment\", 1);\n                    int ret = VActivityManager.get().startActivity(t, 0);\n                    if (ret < 0) {\n                        Toast.makeText(getActivity(), R.string.xposed_installer_not_found, Toast.LENGTH_SHORT).show();\n                    }\n                } catch (Throwable ignored) {\n                    ignored.printStackTrace();\n                }\n                return false;\n            });\n\n            recommend.setOnPreferenceClickListener(preference -> {\n                startActivity(new Intent(getActivity(), RecommendPluginActivity.class));\n                return false;\n            });\n\n            boolean xposedEnabled = VirtualCore.get().isXposedEnabled();\n            if (!xposedEnabled) {\n                getPreferenceScreen().removePreference(moduleManage);\n                getPreferenceScreen().removePreference(recommend);\n            }\n\n            appManage.setOnPreferenceClickListener(preference -> {\n                startActivity(new Intent(getActivity(), AppManageActivity.class));\n                return false;\n            });\n\n            taskManage.setOnPreferenceClickListener(preference -> {\n                startActivity(new Intent(getActivity(), TaskManageActivity.class));\n                return false;\n            });\n\n            faq.setOnPreferenceClickListener(preference -> {\n                Uri uri = Uri.parse(\"https://github.com/android-hacker/VAExposed/wiki/FAQ\");\n                Intent t = new Intent(Intent.ACTION_VIEW, uri);\n                startActivity(t);\n                return false;\n            });\n\n            desktop.setOnPreferenceClickListener(preference -> {\n                startActivity(new Intent(getActivity(), com.google.android.apps.nexuslauncher.SettingsActivity.class));\n                return false;\n            });\n\n            donate.setOnPreferenceClickListener(preference -> {\n                Misc.showDonate(getActivity());\n                return false;\n            });\n            about.setOnPreferenceClickListener(preference -> {\n                startActivity(new Intent(getActivity(), AboutActivity.class));\n                return false;\n            });\n\n            reboot.setOnPreferenceClickListener(preference -> {\n                android.app.AlertDialog alertDialog = new android.app.AlertDialog.Builder(getActivity())\n                        .setTitle(R.string.settings_reboot_title)\n                        .setMessage(getResources().getString(R.string.settings_reboot_content))\n                        .setPositiveButton(android.R.string.yes, (dialog, which) -> {\n                            VirtualCore.get().killAllApps();\n                            Toast.makeText(getActivity(), R.string.reboot_tips_1, Toast.LENGTH_SHORT).show();\n                        })\n                        .setNegativeButton(android.R.string.no, null)\n                        .create();\n                try {\n                    alertDialog.show();\n                } catch (Throwable ignored) {\n                }\n                return false;\n            });\n\n            disableInstaller.setOnPreferenceChangeListener((preference, newValue) -> {\n                if (!(newValue instanceof Boolean)) {\n                    return false;\n                }\n                try {\n                    boolean disable = (boolean) newValue;\n                    PackageManager packageManager = getActivity().getPackageManager();\n                    packageManager.setComponentEnabledSetting(new ComponentName(getActivity().getPackageName(), \"vxp.installer\"),\n                            !disable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,\n                            PackageManager.DONT_KILL_APP);\n                    return true;\n                } catch (Throwable ignored) {\n                    return false;\n                }\n            });\n\n            enableLauncher.setOnPreferenceChangeListener((preference, newValue) -> {\n                if (!(newValue instanceof Boolean)) {\n                    return false;\n                }\n                try {\n                    boolean enable = (boolean) newValue;\n                    PackageManager packageManager = getActivity().getPackageManager();\n                    packageManager.setComponentEnabledSetting(new ComponentName(getActivity().getPackageName(), \"vxp.launcher\"),\n                            enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,\n                            PackageManager.DONT_KILL_APP);\n                    return true;\n                } catch (Throwable ignored) {\n                    return false;\n                }\n            });\n\n            Preference installGms = findPreference(INSTALL_GMS_KEY);\n            installGms.setOnPreferenceClickListener(preference -> {\n                boolean alreadyInstalled = FakeGms.isAlreadyInstalled(getActivity());\n                if (alreadyInstalled) {\n                    FakeGms.uninstallGms(getActivity());\n                } else {\n                    FakeGms.installGms(getActivity());\n                }\n                return true;\n            });\n\n            fileMange.setOnPreferenceClickListener(preference -> {\n                OnlinePlugin.openOrDownload(getActivity(), OnlinePlugin.FILE_MANAGE_PACKAGE,\n                        OnlinePlugin.FILE_MANAGE_URL, getString(R.string.install_file_manager_tips));\n                return false;\n            });\n\n            permissionManage.setOnPreferenceClickListener(preference -> {\n                OnlinePlugin.openOrDownload(getActivity(), OnlinePlugin.PERMISSION_MANAGE_PACKAGE,\n                        OnlinePlugin.PERMISSION_MANAGE_URL, getString(R.string.install_permission_manager_tips));\n                return false;\n            });\n\n            disableXposed.setOnPreferenceChangeListener((preference, newValue) -> {\n\n                if (!(newValue instanceof Boolean)) {\n                    return false;\n                }\n\n                boolean on = (boolean) newValue;\n\n                File disableXposedFile = getActivity().getFileStreamPath(\".disable_xposed\"); // 文件不存在代表是保守模式\n                if (on) {\n                    boolean success;\n                    try {\n                        success = disableXposedFile.createNewFile();\n                    } catch (IOException e) {\n                        success = false;\n                    }\n                    return success;\n                } else {\n                    return !disableXposedFile.exists() || disableXposedFile.delete();\n                }\n            });\n\n            disableResidentNotification.setOnPreferenceChangeListener(((preference, newValue) -> {\n\n                if (!(newValue instanceof Boolean)) {\n                    return false;\n                }\n\n                boolean on = (boolean) newValue;\n\n                File flag = getActivity().getFileStreamPath(Constants.NO_NOTIFICATION_FLAG);\n                if (on) {\n                    boolean success;\n                    try {\n                        success = flag.createNewFile();\n                    } catch (IOException e) {\n                        success = false;\n                    }\n                    return success;\n                } else {\n                    return !flag.exists() || flag.delete();\n                }\n            }));\n\n            if (android.os.Build.VERSION.SDK_INT < 25) {\n                // Android NR1 below do not need this.\n                PreferenceScreen advance = (PreferenceScreen) findPreference(ADVANCE_SETTINGS_KEY);\n                advance.removePreference(disableResidentNotification);\n            }\n\n            allowFakeSignature.setOnPreferenceChangeListener((preference, newValue) -> {\n                if (!(newValue instanceof Boolean)) {\n                    return false;\n                }\n\n                boolean on = (boolean) newValue;\n                File flag = getActivity().getFileStreamPath(Constants.FAKE_SIGNATURE_FLAG);\n                if (on) {\n                    boolean success;\n                    try {\n                        success = flag.createNewFile();\n                    } catch (IOException e) {\n                        success = false;\n                    }\n                    return success;\n                } else {\n                    return !flag.exists() || flag.delete();\n                }\n            });\n\n        }\n\n        private static void dismiss(ProgressDialog dialog) {\n            try {\n                dialog.dismiss();\n            } catch (Throwable ignored) {\n            }\n        }\n\n        protected int dp2px(float dp) {\n            final float scale = getResources().getDisplayMetrics().density;\n            return (int) (dp * scale + 0.5f);\n        }\n\n        @Override\n        public void startActivity(Intent intent) {\n            try {\n                super.startActivity(intent);\n            } catch (Throwable ignored) {\n                Toast.makeText(getActivity(), \"startActivity failed.\", Toast.LENGTH_SHORT).show();\n                ignored.printStackTrace();\n            }\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == VCommends.REQUEST_SELECT_APP) {\n            if (resultCode == RESULT_OK) {\n                finish();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/settings/TaskManageActivity.java",
    "content": "package io.virtualapp.settings;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.glide.GlideUtils;\n\n/**\n * @author weishu\n * @date 18/2/15.\n */\n\npublic class TaskManageActivity extends VActivity {\n\n    private ListView mListView;\n    private List<TaskManageInfo> mInstalledApps = new ArrayList<>();\n    private AppManageAdapter mAdapter;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_list);\n        mListView = (ListView) findViewById(R.id.list);\n        mAdapter = new AppManageAdapter();\n        mListView.setAdapter(mAdapter);\n\n        loadAsync();\n    }\n\n    private void loadAsync() {\n        defer().when(this::loadApp).done((v) -> mAdapter.notifyDataSetChanged());\n    }\n\n    private void loadApp() {\n\n        ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);\n        if (am == null) {\n            return;\n        }\n\n        List<TaskManageInfo> ret = new ArrayList<>();\n        List<ActivityManager.RunningAppProcessInfo> infoList = am.getRunningAppProcesses();\n        if (infoList == null) {\n            return;\n        }\n        List<ActivityManager.RunningAppProcessInfo> retList = new ArrayList<>();\n        String hostPkg = VirtualCore.get().getHostPkg();\n        for (ActivityManager.RunningAppProcessInfo info : infoList) {\n            if (VActivityManager.get().isAppPid(info.pid)) {\n                List<String> pkgList = VActivityManager.get().getProcessPkgList(info.pid);\n                if (pkgList.contains(hostPkg)) {\n                    continue;\n                }\n                String processName = VActivityManager.get().getAppProcessName(info.pid);\n                if (processName != null) {\n                    info.processName = processName;\n                }\n                info.pkgList = pkgList.toArray(new String[pkgList.size()]);\n                info.uid = VUserHandle.getAppId(VActivityManager.get().getUidByPid(info.pid));\n                retList.add(info);\n            }\n        }\n\n        for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : retList) {\n            TaskManageInfo info = new TaskManageInfo();\n            info.name = runningAppProcessInfo.processName;\n            info.pid = runningAppProcessInfo.pid;\n            info.uid = runningAppProcessInfo.uid;\n\n            if (runningAppProcessInfo.pkgList != null) {\n                for (String pkg : runningAppProcessInfo.pkgList) {\n                    InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkg, 0);\n                    if (installedAppInfo != null) {\n                        info.pkgName = installedAppInfo.packageName;\n                        info.path = installedAppInfo.apkPath;\n                    }\n                }\n            }\n            ret.add(info);\n        }\n        mInstalledApps.clear();\n        mInstalledApps.addAll(ret);\n    }\n\n    class AppManageAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            return mInstalledApps.size();\n        }\n\n        @Override\n        public TaskManageInfo getItem(int position) {\n            return mInstalledApps.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ViewHolder holder;\n            if (convertView == null) {\n                holder = new ViewHolder(TaskManageActivity.this, parent);\n                convertView = holder.root;\n                convertView.setTag(holder);\n            } else {\n                holder = (ViewHolder) convertView.getTag();\n            }\n\n            TaskManageInfo item = getItem(position);\n\n            holder.button.setText(R.string.task_manage_uninstall);\n            holder.label.setText(item.name);\n            holder.icon.setImageDrawable(item.icon);\n\n            if (VirtualCore.get().isOutsideInstalled(item.name.toString())) {\n                GlideUtils.loadInstalledPackageIcon(getContext(), item.pkgName, holder.icon, android.R.drawable.sym_def_app_icon);\n            } else {\n                GlideUtils.loadPackageIconFromApkFile(getContext(), item.path, holder.icon, android.R.drawable.sym_def_app_icon);\n            }\n\n            holder.button.setOnClickListener(v -> {\n                VActivityManager.get().killApplicationProcess(item.name.toString(), item.uid);\n                holder.button.postDelayed(TaskManageActivity.this::loadAsync, 300);\n            });\n\n            return convertView;\n        }\n    }\n\n    static class ViewHolder {\n        ImageView icon;\n        TextView label;\n        Button button;\n\n        View root;\n\n        ViewHolder(Context context, ViewGroup parent) {\n            root = LayoutInflater.from(context).inflate(R.layout.item_task_manage, parent, false);\n            icon = root.findViewById(R.id.item_app_icon);\n            label = root.findViewById(R.id.item_app_name);\n            button = root.findViewById(R.id.item_app_button);\n        }\n    }\n\n    static class TaskManageInfo {\n        public String pkgName;\n        public String path;\n        CharSequence name;\n        int uid;\n        int pid;\n        Drawable icon;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/splash/SplashActivity.java",
    "content": "package io.virtualapp.splash;\n\nimport android.os.Bundle;\nimport android.view.WindowManager;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport io.virtualapp.R;\nimport io.virtualapp.VCommends;\nimport io.virtualapp.abs.ui.VActivity;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.NewHomeActivity;\nimport jonathanfinerty.once.Once;\n\npublic class SplashActivity extends VActivity {\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        @SuppressWarnings(\"unused\")\n        boolean enterGuide = !Once.beenDone(Once.THIS_APP_INSTALL, VCommends.TAG_NEW_VERSION);\n        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                WindowManager.LayoutParams.FLAG_FULLSCREEN);\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_splash);\n        VUiKit.defer().when(() -> {\n            long time = System.currentTimeMillis();\n            doActionInThread();\n            time = System.currentTimeMillis() - time;\n            long delta = 100L - time;\n            if (delta > 0) {\n                VUiKit.sleep(delta);\n            }\n        }).done((res) -> {\n            NewHomeActivity.goHome(this);\n            finish();\n        });\n    }\n\n    private void doActionInThread() {\n        if (!VirtualCore.get().isEngineLaunched()) {\n            VirtualCore.get().waitForEngine();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/sys/Installd.java",
    "content": "package io.virtualapp.sys;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport com.lody.virtual.GmsSupport;\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.DeviceUtil;\nimport com.lody.virtual.os.VUserInfo;\nimport com.lody.virtual.os.VUserManager;\nimport com.lody.virtual.remote.InstallResult;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.VCommends;\nimport io.virtualapp.XApp;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.models.AppData;\nimport io.virtualapp.home.models.AppInfoLite;\nimport io.virtualapp.home.models.MultiplePackageAppData;\nimport io.virtualapp.home.models.PackageAppData;\nimport io.virtualapp.home.repo.PackageAppDataStorage;\n\n/**\n * author: weishu on 18/3/19.\n */\npublic class Installd {\n\n    public interface UpdateListener {\n        void update(AppData model);\n\n        void fail(String msg);\n    }\n\n    public static void addApp(AppInfoLite info, UpdateListener refreshListener) {\n        class AddResult {\n            private PackageAppData appData;\n            private int userId;\n            private boolean justEnableHidden;\n        }\n        AddResult addResult = new AddResult();\n        VUiKit.defer().when(() -> {\n            InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);\n            addResult.justEnableHidden = installedAppInfo != null;\n\n            if (info.disableMultiVersion) {\n                addResult.justEnableHidden = false;\n            }\n            if (addResult.justEnableHidden) {\n                int[] userIds = installedAppInfo.getInstalledUsers();\n                int nextUserId = userIds.length;\n                /*\n                  Input : userIds = {0, 1, 3}\n                  Output: nextUserId = 2\n                 */\n                for (int i = 0; i < userIds.length; i++) {\n                    if (userIds[i] != i) {\n                        nextUserId = i;\n                        break;\n                    }\n                }\n                addResult.userId = nextUserId;\n\n                if (VUserManager.get().getUserInfo(nextUserId) == null) {\n                    // user not exist, create it automatically.\n                    String nextUserName = \"Space \" + (nextUserId + 1);\n                    VUserInfo newUserInfo = VUserManager.get().createUser(nextUserName, VUserInfo.FLAG_ADMIN);\n                    if (newUserInfo == null) {\n                        throw new IllegalStateException();\n                    }\n                }\n                boolean success = VirtualCore.get().installPackageAsUser(nextUserId, info.packageName);\n                if (!success) {\n                    throw new IllegalStateException();\n                }\n            } else {\n                PackageInfo pkgInfo = null;\n                try {\n                    pkgInfo = XApp.getApp().getPackageManager().getPackageArchiveInfo(info.path, 0);\n                    pkgInfo.applicationInfo.sourceDir = info.path;\n                    pkgInfo.applicationInfo.publicSourceDir = info.path;\n                } catch (Exception e) {\n                }\n                if(pkgInfo != null) {\n                    PackageAppData data = PackageAppDataStorage.get().acquire(pkgInfo.applicationInfo);\n                    addResult.appData = data;\n                    data.isInstalling = true;\n                    data.isFirstOpen = false;\n                    if (refreshListener != null) {\n                        refreshListener.update(data);\n                    }\n                }\n\n                InstallResult res = addVirtualApp(info);\n                if (!res.isSuccess) {\n                    if (addResult.appData != null) {\n                        // mView.removeAppToLauncher(addResult.appData);\n                    }\n                    throw new IllegalStateException(res.error);\n                }\n            }\n        }).then((res) -> {\n            if (addResult.appData == null) {\n                addResult.appData = PackageAppDataStorage.get().acquire(info.packageName);\n            }\n        }).done(res -> {\n            boolean multipleVersion = addResult.justEnableHidden && addResult.userId != 0;\n            if (!multipleVersion) {\n                PackageAppData data = addResult.appData;\n                data.isInstalling = false;\n                data.isLoading = true;\n\n                if (refreshListener != null) {\n                    refreshListener.update(data);\n                }\n                handleOptApp(data, info.packageName, true, refreshListener);\n            } else {\n                MultiplePackageAppData data = new MultiplePackageAppData(addResult.appData, addResult.userId);\n                data.isInstalling = false;\n                data.isLoading = true;\n\n                if (refreshListener != null) {\n                    refreshListener.update(data);\n                }\n                handleOptApp(data, info.packageName, false, refreshListener);\n            }\n        }).fail(result -> {\n            if (refreshListener != null) {\n                refreshListener.fail(result.getMessage());\n\n            }\n        });\n    }\n\n\n    private static void handleOptApp(AppData data, String packageName, boolean needOpt, UpdateListener refreshListener) {\n        VUiKit.defer().when(() -> {\n            long time = System.currentTimeMillis();\n            if (needOpt) {\n                try {\n                    VirtualCore.get().preOpt(packageName);\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n            time = System.currentTimeMillis() - time;\n            if (time < 1500L) {\n                try {\n                    Thread.sleep(1500L - time);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n        }).done((res) -> {\n            if (data instanceof PackageAppData) {\n                ((PackageAppData) data).isLoading = false;\n                ((PackageAppData) data).isFirstOpen = true;\n            } else if (data instanceof MultiplePackageAppData) {\n                ((MultiplePackageAppData) data).isLoading = false;\n                ((MultiplePackageAppData) data).isFirstOpen = true;\n            }\n            if (refreshListener != null) {\n                refreshListener.update(data);\n            }\n        });\n    }\n\n    public static InstallResult addVirtualApp(AppInfoLite info) {\n        int flags = InstallStrategy.COMPARE_VERSION | InstallStrategy.SKIP_DEX_OPT;\n        info.fastOpen = false; // disable fast open for compile.\n        if (DeviceUtil.isMeizuBelowN()) {\n            info.fastOpen = true;\n        }\n        if (info.fastOpen) {\n            flags |= InstallStrategy.DEPEND_SYSTEM_IF_EXIST;\n        }\n        if (info.disableMultiVersion) {\n            flags |= InstallStrategy.UPDATE_IF_EXIST;\n        }\n        return VirtualCore.get().installPackage(info.path, flags);\n    }\n\n    private static ArrayList<AppInfoLite> getAppInfoLiteFromPath(Context context, String path) {\n        if (context == null) {\n            return null;\n        }\n        PackageInfo pkgInfo = null;\n        try {\n            pkgInfo = context.getPackageManager().getPackageArchiveInfo(path, PackageManager.GET_META_DATA);\n            pkgInfo.applicationInfo.sourceDir = path;\n            pkgInfo.applicationInfo.publicSourceDir = path;\n        } catch (Exception e) {\n            // Ignore\n        }\n        if (pkgInfo == null) {\n            return null;\n        }\n\n        if (TextUtils.equals(VirtualCore.TAICHI_PACKAGE, pkgInfo.packageName)) {\n            return null;\n        }\n\n        if (VirtualCore.get().getHostPkg().equals(pkgInfo.packageName)) {\n            Toast.makeText(VirtualCore.get().getContext(), R.string.install_self_eggs, Toast.LENGTH_SHORT).show();\n            return null;\n        }\n\n        boolean isXposed = pkgInfo.applicationInfo.metaData != null\n                && pkgInfo.applicationInfo.metaData.containsKey(\"xposedmodule\");\n        AppInfoLite appInfoLite = new AppInfoLite(pkgInfo.packageName, path, false, isXposed);\n        ArrayList<AppInfoLite> dataList = new ArrayList<>();\n        dataList.add(appInfoLite);\n        return dataList;\n    }\n\n    public static void handleRequestFromFile(Context context, String path) {\n\n        ArrayList<AppInfoLite> dataList = getAppInfoLiteFromPath(context, path);\n        if (dataList == null) {\n            return;\n        }\n        startInstallerActivity(context, dataList);\n    }\n\n    public static void startInstallerActivity(Context context, ArrayList<AppInfoLite> data) {\n        if (context == null) {\n            return;\n        }\n        Intent intent = new Intent(context, InstallerActivity.class);\n        intent.putParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST, data);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n    }\n\n    public static void addGmsSupport() {\n        List<String> gApps = new ArrayList<>();\n        gApps.addAll(GmsSupport.GOOGLE_APP);\n        gApps.addAll(GmsSupport.GOOGLE_SERVICE);\n\n        VirtualCore core = VirtualCore.get();\n        final int userId = 0;\n\n        ArrayList<AppInfoLite> toInstalled = new ArrayList<>();\n        for (String packageName : gApps) {\n            if (core.isAppInstalledAsUser(userId, packageName)) {\n                continue;\n            }\n            ApplicationInfo info = null;\n            try {\n                info = VirtualCore.get().getUnHookPackageManager().getApplicationInfo(packageName, 0);\n            } catch (PackageManager.NameNotFoundException e) {\n                // Ignore\n            }\n            if (info == null || info.sourceDir == null) {\n                continue;\n            }\n\n            AppInfoLite lite = new AppInfoLite(info.packageName, info.sourceDir, false, true);\n            toInstalled.add(lite);\n        }\n        startInstallerActivity(VirtualCore.get().getContext(), toInstalled);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/sys/InstallerActivity.java",
    "content": "package io.virtualapp.sys;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.EncodeUtils;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport io.virtualapp.R;\nimport io.virtualapp.VCommends;\nimport io.virtualapp.abs.ui.VUiKit;\nimport io.virtualapp.home.LoadingActivity;\nimport io.virtualapp.home.models.AppData;\nimport io.virtualapp.home.models.AppInfoLite;\n\n/**\n * author: weishu on 18/3/19.\n */\npublic class InstallerActivity extends AppCompatActivity {\n\n    private TextView mTips;\n    private Button mLeft;\n    private Button mRight;\n    private ProgressBar mProgressBar;\n    private TextView mProgressText;\n\n    private int mInstallCount = 0;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_install);\n\n        mTips = (TextView) findViewById(R.id.installer_text);\n        mLeft = (Button) findViewById(R.id.installer_left_button);\n        mRight = (Button) findViewById(R.id.installer_right_button);\n        mProgressBar = (ProgressBar) findViewById(R.id.installer_loading);\n        mProgressText = (TextView) findViewById(R.id.installer_progress_text);\n\n        handleIntent(getIntent());\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        handleIntent(intent);\n    }\n\n    @Override\n    public void onBackPressed() {\n        // do nothing.\n        if (mInstallCount > 0) {\n\n        }\n    }\n\n    private void handleIntent(Intent intent) {\n        if (intent == null) {\n            finish();\n            return;\n        }\n\n        ArrayList<AppInfoLite> dataList = intent.getParcelableArrayListExtra(VCommends.EXTRA_APP_INFO_LIST);\n        if (dataList == null) {\n            handleSystemIntent(intent);\n        } else {\n            handleSelfIntent(dataList);\n        }\n    }\n\n    private void handleSelfIntent(ArrayList<AppInfoLite> appList) {\n        if (appList != null) {\n            boolean showTip = false;\n            int size = appList.size();\n            mInstallCount = size;\n\n            if (dealUpdate(appList)) {\n                return;\n            }\n\n            for (int i = 0; i < size; i++) {\n                AppInfoLite info = appList.get(i);\n                if (new File(info.path).length() > 1024 * 1024 * 24) {\n                    showTip = true;\n                }\n\n                addApp(info);\n            }\n            if (showTip) {\n                Toast.makeText(this, R.string.large_app_install_tips, Toast.LENGTH_SHORT).show();\n            }\n        }\n\n    }\n\n    private void addApp(AppInfoLite appInfoLite) {\n        Installd.addApp(appInfoLite, new Installd.UpdateListener() {\n            @Override\n            public void update(AppData model) {\n                runOnUiThread(() -> {\n                            if (model.isInstalling()) {\n                                mProgressText.setVisibility(View.VISIBLE);\n                                mProgressBar.setVisibility(View.VISIBLE);\n                                mProgressText.setText(getResources().getString(R.string.add_app_installing_tips, model.getName()));\n                            } else if (model.isLoading()) {\n                                mProgressText.setVisibility(View.VISIBLE);\n                                mProgressBar.setVisibility(View.VISIBLE);\n                                mProgressText.setText(getResources().getString(R.string.add_app_loading_tips, model.getName()));\n                            } else {\n                                mInstallCount--;\n                                if (mInstallCount <= 0) {\n                                    mInstallCount = 0;\n                                    // only dismiss when the app is the last to install.\n                                    mProgressText.setText(getResources().getString(R.string.add_app_loading_complete, model.getName()));\n                                    mProgressText.postDelayed(() -> {\n                                        mProgressBar.setVisibility(View.GONE);\n\n                                        mLeft.setVisibility(View.VISIBLE);\n                                        mLeft.setText(R.string.install_complete);\n                                        mLeft.setOnClickListener((vv) -> finish());\n\n                                        mRight.setVisibility(View.VISIBLE);\n                                        mRight.setText(R.string.install_complete_and_open);\n                                        mRight.setOnClickListener((vv) -> {\n                                            LoadingActivity.launch(getApplicationContext(), appInfoLite.packageName, 0);\n                                            finish();\n                                        });\n                                    }, 500);\n                                }\n                            }\n                        }\n                );\n            }\n\n            @Override\n            public void fail(String msg) {\n                if (msg == null) {\n                    msg = \"Unknown\";\n                }\n\n                mProgressText.setText(getResources().getString(R.string.install_fail, msg));\n                mProgressText.postDelayed(() -> {\n                    mProgressBar.setVisibility(View.GONE);\n                    mRight.setVisibility(View.VISIBLE);\n                    mRight.setText(R.string.install_complete);\n                    mRight.setOnClickListener((vv) -> finish());\n                }, 500);\n            }\n        });\n    }\n\n    private boolean dealUpdate(List<AppInfoLite> appList) {\n        if (appList == null || appList.size() != 1) {\n            return false;\n        }\n        AppInfoLite appInfoLite = appList.get(0);\n        if (appInfoLite == null) {\n            return false;\n        }\n\n        List<String> magicApps = Arrays.asList(EncodeUtils.decode(\"Y29tLmxiZS5wYXJhbGxlbA==\"), // com.lbe.parallel\n                EncodeUtils.decode(\"aW8udmlydHVhbGFwcC5zYW5kdnhwb3NlZA==\"), // io.virtualapp.sandvxposed\n                EncodeUtils.decode(\"Y29tLnNrLnNwYXRjaA==\"), // com.sk.spatch\n                EncodeUtils.decode(\"Y29tLnFpaG9vLm1hZ2lj\"), // com.qihoo.magic\n                EncodeUtils.decode(\"Y29tLmRvdWJsZW9wZW4=\")); // com.doubleopen\n\n        if (magicApps.contains(appInfoLite.packageName)) {\n            Toast.makeText(VirtualCore.get().getContext(), R.string.install_self_eggs, Toast.LENGTH_SHORT).show();\n        }\n\n        if (appInfoLite.disableMultiVersion) {\n            return false;\n        }\n        InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(appInfoLite.packageName, 0);\n        if (installedAppInfo == null) {\n            return false;\n        }\n        String currentVersion;\n        String toInstalledVersion;\n        int currentVersionCode;\n        int toInstalledVersionCode;\n        PackageManager packageManager = getPackageManager();\n        if (packageManager == null) {\n            return false;\n        }\n        try {\n            PackageInfo applicationInfo = installedAppInfo.getPackageInfo(0);\n            currentVersion = applicationInfo.versionName;\n            currentVersionCode = applicationInfo.versionCode;\n\n            PackageInfo packageArchiveInfo = packageManager.getPackageArchiveInfo(appInfoLite.path, 0);\n            toInstalledVersion = packageArchiveInfo.versionName;\n            toInstalledVersionCode = packageArchiveInfo.versionCode;\n\n            String multiVersionUpdate = getResources().getString(currentVersionCode == toInstalledVersionCode ? R.string.multi_version_cover : (\n                    currentVersionCode < toInstalledVersionCode ? R.string.multi_version_upgrade : R.string.multi_version_downgrade\n            ));\n            AlertDialog alertDialog = new AlertDialog.Builder(this)\n                    .setTitle(R.string.multi_version_tip_title)\n                    .setMessage(getResources().getString(R.string.multi_version_tips_content, currentVersion, toInstalledVersion))\n                    .setPositiveButton(R.string.multi_version_multi, (dialog, which) -> {\n                        addApp(appInfoLite);\n                    })\n                    .setNegativeButton(multiVersionUpdate, ((dialog, which) -> {\n                        appInfoLite.disableMultiVersion = true;\n                        addApp(appInfoLite);\n                    }))\n                    .create();\n            alertDialog.show();\n        } catch (Throwable ignored) {\n            return false;\n        }\n        return true;\n    }\n\n    private void handleSystemIntent(Intent intent) {\n\n        Context context = VirtualCore.get().getContext();\n        String path;\n        try {\n            path = FileUtils.getFileFromUri(context, intent.getData());\n        } catch (Throwable e) {\n            e.printStackTrace();\n            return;\n        }\n        PackageInfo pkgInfo = null;\n        try {\n            pkgInfo = context.getPackageManager().getPackageArchiveInfo(path, PackageManager.GET_META_DATA);\n            pkgInfo.applicationInfo.sourceDir = path;\n            pkgInfo.applicationInfo.publicSourceDir = path;\n        } catch (Exception e) {\n            // Ignore\n        }\n        if (pkgInfo == null) {\n            finish();\n            return;\n        }\n\n        boolean isXposed = pkgInfo.applicationInfo.metaData != null\n                && pkgInfo.applicationInfo.metaData.containsKey(\"xposedmodule\");\n\n        InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(pkgInfo.packageName, 0);\n\n        String tipsText;\n        String rightString;\n        String leftString = getResources().getString(android.R.string.cancel);\n\n        PackageManager packageManager = getPackageManager();\n        if (packageManager == null) {\n            finish();\n            return;\n        }\n\n        final String packageName = pkgInfo.packageName;\n        String toInstalledVersion = pkgInfo.versionName;\n        int toInstalledVersionCode = pkgInfo.versionCode;\n        CharSequence label = packageName;\n\n        if (installedAppInfo != null) {\n            String currentVersion;\n            int currentVersionCode;\n\n            PackageInfo applicationInfo = installedAppInfo.getPackageInfo(0);\n            if (applicationInfo == null) {\n                finish();\n                return;\n            }\n            currentVersion = applicationInfo.versionName;\n            currentVersionCode = applicationInfo.versionCode;\n\n            label = applicationInfo.applicationInfo.loadLabel(packageManager);\n\n            String multiVersionUpdate = getResources().getString(currentVersionCode == toInstalledVersionCode ? R.string.multi_version_cover : (\n                    currentVersionCode < toInstalledVersionCode ? R.string.multi_version_upgrade : R.string.multi_version_downgrade\n            ));\n\n            tipsText = getResources().getString(R.string.install_package_version_tips, currentVersion, toInstalledVersion);\n            rightString = multiVersionUpdate;\n\n        } else {\n            tipsText = getResources().getString(R.string.install_package, label);\n            rightString = getResources().getString(R.string.install);\n        }\n\n        final CharSequence apkName = label;\n        mTips.setText(tipsText);\n        mLeft.setText(leftString);\n        mRight.setText(rightString);\n\n        mLeft.setOnClickListener(v -> finish());\n        mRight.setOnClickListener(v -> {\n\n            mProgressBar.setVisibility(View.VISIBLE);\n            mTips.setVisibility(View.GONE);\n            mLeft.setVisibility(View.GONE);\n            mRight.setEnabled(false);\n\n            VUiKit.defer().when(() -> {\n                return VirtualCore.get().installPackage(path, InstallStrategy.UPDATE_IF_EXIST);\n            }).done((res) -> {\n                // install success\n                mTips.setVisibility(View.GONE);\n                mProgressText.setVisibility(View.VISIBLE);\n                mProgressText.setText(getResources().getString(R.string.add_app_loading_complete, apkName));\n                mProgressBar.setVisibility(View.GONE);\n                mRight.setVisibility(View.VISIBLE);\n                mRight.setEnabled(true);\n                mRight.setText(R.string.install_complete_and_open);\n                mRight.setOnClickListener(vv -> {\n                    LoadingActivity.launch(this, packageName, 0);\n                    finish();\n                });\n                mLeft.setVisibility(View.VISIBLE);\n                mLeft.setEnabled(true);\n                mLeft.setText(res.isSuccess ? getResources().getString(R.string.install_complete) :\n                        getResources().getString(R.string.install_fail, res.error));\n                mLeft.setOnClickListener((vv) -> finish());\n            }).fail((res) -> {\n                String msg = res.getMessage();\n                if (msg == null) {\n                    msg = \"Unknown\";\n                }\n                mProgressText.setVisibility(View.VISIBLE);\n                mProgressText.setText(getResources().getString(R.string.install_fail, msg));\n                mRight.setEnabled(true);\n                mProgressBar.setVisibility(View.GONE);\n                mRight.setText(android.R.string.ok);\n                mRight.setOnClickListener((vv) -> finish());\n            });\n        });\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/sys/ShareBridgeActivity.java",
    "content": "package io.virtualapp.sys;\n\nimport android.app.Activity;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.ipc.VPackageManager;\n\nimport java.util.List;\n\nimport io.virtualapp.R;\n\n/**\n * author: weishu on 18/3/16.\n */\npublic class ShareBridgeActivity extends AppCompatActivity {\n    private SharedAdapter mAdapter;\n    private List<ResolveInfo> mShareComponents;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        Intent intent = getIntent();\n        String action = intent.getAction();\n        String type = intent.getType();\n\n        intent.setComponent(null);\n\n        if (!Intent.ACTION_SEND.equals(action)) {\n            finish();\n            return;\n        }\n\n        try {\n            mShareComponents = VPackageManager.get().\n                    queryIntentActivities(new Intent(Intent.ACTION_SEND), type, 0, 0); // multi-user?\n        } catch (Throwable ignored) {\n        }\n\n        if (mShareComponents == null || mShareComponents.size() == 0) {\n            finish();\n            return;\n        }\n\n        setContentView(R.layout.activity_list);\n        ListView mListView = (ListView) findViewById(R.id.list);\n        mAdapter = new SharedAdapter();\n        mListView.setAdapter(mAdapter);\n\n        mListView.setOnItemClickListener((parent, view, position, id) -> {\n            try {\n                ResolveInfo item = mAdapter.getItem(position);\n                Intent t = new Intent(intent);\n                t.setComponent(new ComponentName(item.activityInfo.packageName, item.activityInfo.name));\n                VActivityManager.get().startActivity(t, 0);\n            } catch (Throwable e) {\n                Toast.makeText(getApplicationContext(), R.string.shared_to_vxp_failed, Toast.LENGTH_SHORT).show();\n            }\n            finish();\n        });\n    }\n\n    private class SharedAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            return mShareComponents.size();\n        }\n\n        @Override\n        public ResolveInfo getItem(int position) {\n            return mShareComponents.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ViewHolder holder;\n            if (convertView == null) {\n                holder = new ViewHolder(getActivity(), parent);\n                convertView = holder.root;\n                convertView.setTag(holder);\n            } else {\n                holder = (ViewHolder) convertView.getTag();\n            }\n\n            ResolveInfo item = getItem(position);\n            PackageManager packageManager = getPackageManager();\n            try {\n                holder.label.setText(item.loadLabel(packageManager));\n            } catch (Throwable e) {\n                holder.label.setText(R.string.package_state_unknown);\n            }\n            try {\n                holder.icon.setImageDrawable(item.loadIcon(packageManager));\n            } catch (Throwable e) {\n                holder.icon.setImageDrawable(getResources().getDrawable(android.R.drawable.sym_def_app_icon));\n            }\n\n            return convertView;\n        }\n    }\n\n    static class ViewHolder {\n        ImageView icon;\n        TextView label;\n\n        View root;\n\n        ViewHolder(Context context, ViewGroup parent) {\n            root = LayoutInflater.from(context).inflate(R.layout.item_share, parent, false);\n            icon = root.findViewById(R.id.item_share_icon);\n            label = root.findViewById(R.id.item_share_name);\n        }\n    }\n\n    private Activity getActivity() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/update/VAVersionService.java",
    "content": "package io.virtualapp.update;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.allenliu.versionchecklib.core.AVersionService;\nimport com.allenliu.versionchecklib.core.AllenChecker;\nimport com.allenliu.versionchecklib.core.VersionParams;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.virtualapp.R;\n\n/**\n * @author weishu\n * @date 18/1/4.\n */\n\npublic class VAVersionService extends AVersionService {\n    private static final String TAG = \"VAVersionService\";\n\n    private static final long CHECK_INTERVAL = TimeUnit.HOURS.toMillis(1);\n\n    private static final String KEY_SHOW_TIP = \"show_tips\";\n\n    private static long sLastCheckTime;\n\n    static {\n        AllenChecker.init(false);\n    }\n\n    public static final String CHECK_VERION_URL = \"http://vaexposed.weishu.me/update.json\";\n\n    @Override\n    public void onResponses(AVersionService service, String response) {\n        try {\n            JSONObject versionInfo = new JSONObject(response);\n//            {\n//                url: \"download url\",\n//                versionCode: 3,\n//                updateMessage: \"Android 7.0\"\n//            }\n            String url = versionInfo.getString(\"url\");\n            int versionCode = versionInfo.getInt(\"versionCode\");\n            String updateMessage = versionInfo.getString(\"updateMessage\");\n\n            int currentVersion = getCurrentVersionCode(this);\n            if (currentVersion < versionCode) {\n                showVersionDialog(url, getResources().getString(R.string.new_version_detected), updateMessage);\n            } else {\n                boolean showTip = versionParams != null && versionParams.getParamBundle() != null\n                        && versionParams.getParamBundle().getBoolean(KEY_SHOW_TIP, false);\n                if (showTip) {\n                    Toast.makeText(getApplicationContext(), R.string.version_is_latest, Toast.LENGTH_SHORT).show();\n                }\n            }\n\n        } catch (JSONException e) {\n            Log.e(TAG, \"version info parse error!!\", e);\n        } catch (Throwable e) {\n            Log.e(TAG, \"check version failed:\", e);\n        } finally {\n            stopSelf();\n        }\n    }\n\n    public static void checkUpdateImmediately(Context context, boolean showTip) {\n        Bundle bundle = new Bundle();\n        bundle.putBoolean(KEY_SHOW_TIP, showTip);\n\n        VersionParams.Builder builder = new VersionParams.Builder()\n                .setRequestUrl(CHECK_VERION_URL)\n                .setShowDownloadingDialog(false)\n                .setParamBundle(bundle)\n                .setService(VAVersionService.class);\n\n        AllenChecker.startVersionCheck(context, builder.build());\n    }\n\n    public static void checkUpdate(Context context, boolean showTip) {\n        long now = SystemClock.elapsedRealtime();\n        if (now - sLastCheckTime > CHECK_INTERVAL) {\n            checkUpdateImmediately(context, showTip);\n            sLastCheckTime = now;\n        }\n    }\n\n    private static int getCurrentVersionCode(Context context) {\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            return pi.versionCode;\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/utils/DialogUtil.java",
    "content": "package io.virtualapp.utils;\n\nimport android.support.v7.app.AlertDialog;\n\n/**\n * @author weishu\n * @date 2018/7/5.\n */\npublic class DialogUtil {\n    public static void showDialog(AlertDialog dialog) {\n        if (dialog == null) {\n            return;\n        }\n        try {\n            dialog.show();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/utils/HanziToPinyin.java",
    "content": "package io.virtualapp.utils;\n/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Locale;\n\n/**\n * An object to convert Chinese character to its corresponding pinyin string. For characters with\n * multiple possible pinyin string, only one is selected according to collator. Polyphone is not\n * supported in this implementation. This class is implemented to achieve the best runtime\n * performance and minimum runtime resources with tolerable sacrifice of accuracy. This\n * implementation highly depends on zh_CN ICU collation data and must be always synchronized with\n * ICU.\n * <p>\n * Currently this file is aligned to zh.txt in ICU 4.6\n */\npublic class HanziToPinyin {\n    private static final String TAG = \"HanziToPinyin\";\n\n    // Turn on this flag when we want to check internal data structure.\n    private static final boolean DEBUG = false;\n\n    /**\n     * Unihans array.\n     * <p>\n     * Each unihans is the first one within same pinyin when collator is zh_CN.\n     */\n    public static final char[] UNIHANS = {\n            '\\u963f', '\\u54ce', '\\u5b89', '\\u80ae', '\\u51f9', '\\u516b',\n            '\\u6300', '\\u6273', '\\u90a6', '\\u52f9', '\\u9642', '\\u5954',\n            '\\u4f3b', '\\u5c44', '\\u8fb9', '\\u706c', '\\u618b', '\\u6c43',\n            '\\u51ab', '\\u7676', '\\u5cec', '\\u5693', '\\u5072', '\\u53c2',\n            '\\u4ed3', '\\u64a1', '\\u518a', '\\u5d7e', '\\u66fd', '\\u66fe',\n            '\\u5c64', '\\u53c9', '\\u8286', '\\u8fbf', '\\u4f25', '\\u6284',\n            '\\u8f66', '\\u62bb', '\\u6c88', '\\u6c89', '\\u9637', '\\u5403',\n            '\\u5145', '\\u62bd', '\\u51fa', '\\u6b3b', '\\u63e3', '\\u5ddb',\n            '\\u5205', '\\u5439', '\\u65fe', '\\u9034', '\\u5472', '\\u5306',\n            '\\u51d1', '\\u7c97', '\\u6c46', '\\u5d14', '\\u90a8', '\\u6413',\n            '\\u5491', '\\u5446', '\\u4e39', '\\u5f53', '\\u5200', '\\u561a',\n            '\\u6265', '\\u706f', '\\u6c10', '\\u55f2', '\\u7538', '\\u5201',\n            '\\u7239', '\\u4e01', '\\u4e1f', '\\u4e1c', '\\u543a', '\\u53be',\n            '\\u8011', '\\u8968', '\\u5428', '\\u591a', '\\u59b8', '\\u8bf6',\n            '\\u5940', '\\u97a5', '\\u513f', '\\u53d1', '\\u5e06', '\\u531a',\n            '\\u98de', '\\u5206', '\\u4e30', '\\u8985', '\\u4ecf', '\\u7d11',\n            '\\u4f15', '\\u65ee', '\\u4f85', '\\u7518', '\\u5188', '\\u768b',\n            '\\u6208', '\\u7ed9', '\\u6839', '\\u522f', '\\u5de5', '\\u52fe',\n            '\\u4f30', '\\u74dc', '\\u4e56', '\\u5173', '\\u5149', '\\u5f52',\n            '\\u4e28', '\\u5459', '\\u54c8', '\\u548d', '\\u4f44', '\\u592f',\n            '\\u8320', '\\u8bc3', '\\u9ed2', '\\u62eb', '\\u4ea8', '\\u5677',\n            '\\u53ff', '\\u9f41', '\\u4e6f', '\\u82b1', '\\u6000', '\\u72bf',\n            '\\u5ddf', '\\u7070', '\\u660f', '\\u5419', '\\u4e0c', '\\u52a0',\n            '\\u620b', '\\u6c5f', '\\u827d', '\\u9636', '\\u5dfe', '\\u5755',\n            '\\u5182', '\\u4e29', '\\u51e5', '\\u59e2', '\\u5658', '\\u519b',\n            '\\u5494', '\\u5f00', '\\u520a', '\\u5ffc', '\\u5c3b', '\\u533c',\n            '\\u808e', '\\u52a5', '\\u7a7a', '\\u62a0', '\\u625d', '\\u5938',\n            '\\u84af', '\\u5bbd', '\\u5321', '\\u4e8f', '\\u5764', '\\u6269',\n            '\\u5783', '\\u6765', '\\u5170', '\\u5577', '\\u635e', '\\u808b',\n            '\\u52d2', '\\u5d1a', '\\u5215', '\\u4fe9', '\\u5941', '\\u826f',\n            '\\u64a9', '\\u5217', '\\u62ce', '\\u5222', '\\u6e9c', '\\u56d6',\n            '\\u9f99', '\\u779c', '\\u565c', '\\u5a08', '\\u7567', '\\u62a1',\n            '\\u7f57', '\\u5463', '\\u5988', '\\u57cb', '\\u5ada', '\\u7264',\n            '\\u732b', '\\u4e48', '\\u5445', '\\u95e8', '\\u753f', '\\u54aa',\n            '\\u5b80', '\\u55b5', '\\u4e5c', '\\u6c11', '\\u540d', '\\u8c2c',\n            '\\u6478', '\\u54de', '\\u6bea', '\\u55ef', '\\u62cf', '\\u8149',\n            '\\u56e1', '\\u56d4', '\\u5b6c', '\\u7592', '\\u5a1e', '\\u6041',\n            '\\u80fd', '\\u59ae', '\\u62c8', '\\u5b22', '\\u9e1f', '\\u634f',\n            '\\u56dc', '\\u5b81', '\\u599e', '\\u519c', '\\u7fba', '\\u5974',\n            '\\u597b', '\\u759f', '\\u9ec1', '\\u90cd', '\\u5594', '\\u8bb4',\n            '\\u5991', '\\u62cd', '\\u7705', '\\u4e53', '\\u629b', '\\u5478',\n            '\\u55b7', '\\u5309', '\\u4e15', '\\u56e8', '\\u527d', '\\u6c15',\n            '\\u59d8', '\\u4e52', '\\u948b', '\\u5256', '\\u4ec6', '\\u4e03',\n            '\\u6390', '\\u5343', '\\u545b', '\\u6084', '\\u767f', '\\u4eb2',\n            '\\u72c5', '\\u828e', '\\u4e18', '\\u533a', '\\u5cd1', '\\u7f3a',\n            '\\u590b', '\\u5465', '\\u7a63', '\\u5a06', '\\u60f9', '\\u4eba',\n            '\\u6254', '\\u65e5', '\\u8338', '\\u53b9', '\\u909a', '\\u633c',\n            '\\u5827', '\\u5a51', '\\u77a4', '\\u637c', '\\u4ee8', '\\u6be2',\n            '\\u4e09', '\\u6852', '\\u63bb', '\\u95aa', '\\u68ee', '\\u50e7',\n            '\\u6740', '\\u7b5b', '\\u5c71', '\\u4f24', '\\u5f30', '\\u5962',\n            '\\u7533', '\\u8398', '\\u6552', '\\u5347', '\\u5c38', '\\u53ce',\n            '\\u4e66', '\\u5237', '\\u8870', '\\u95e9', '\\u53cc', '\\u8c01',\n            '\\u542e', '\\u8bf4', '\\u53b6', '\\u5fea', '\\u635c', '\\u82cf',\n            '\\u72fb', '\\u590a', '\\u5b59', '\\u5506', '\\u4ed6', '\\u56fc',\n            '\\u574d', '\\u6c64', '\\u5932', '\\u5fd1', '\\u71a5', '\\u5254',\n            '\\u5929', '\\u65eb', '\\u5e16', '\\u5385', '\\u56f2', '\\u5077',\n            '\\u51f8', '\\u6e4d', '\\u63a8', '\\u541e', '\\u4e47', '\\u7a75',\n            '\\u6b6a', '\\u5f2f', '\\u5c23', '\\u5371', '\\u6637', '\\u7fc1',\n            '\\u631d', '\\u4e4c', '\\u5915', '\\u8672', '\\u4eda', '\\u4e61',\n            '\\u7071', '\\u4e9b', '\\u5fc3', '\\u661f', '\\u51f6', '\\u4f11',\n            '\\u5401', '\\u5405', '\\u524a', '\\u5743', '\\u4e2b', '\\u6079',\n            '\\u592e', '\\u5e7a', '\\u503b', '\\u4e00', '\\u56d9', '\\u5e94',\n            '\\u54df', '\\u4f63', '\\u4f18', '\\u625c', '\\u56e6', '\\u66f0',\n            '\\u6655', '\\u7b60', '\\u7b7c', '\\u5e00', '\\u707d', '\\u5142',\n            '\\u5328', '\\u50ae', '\\u5219', '\\u8d3c', '\\u600e', '\\u5897',\n            '\\u624e', '\\u635a', '\\u6cbe', '\\u5f20', '\\u957f', '\\u9577',\n            '\\u4f4b', '\\u8707', '\\u8d1e', '\\u4e89', '\\u4e4b', '\\u5cd9',\n            '\\u5ea2', '\\u4e2d', '\\u5dde', '\\u6731', '\\u6293', '\\u62fd',\n            '\\u4e13', '\\u5986', '\\u96b9', '\\u5b92', '\\u5353', '\\u4e72',\n            '\\u5b97', '\\u90b9', '\\u79df', '\\u94bb', '\\u539c', '\\u5c0a',\n            '\\u6628', '\\u5159', '\\u9fc3', '\\u9fc4',};\n\n    /**\n     * Pinyin array.\n     * <p>\n     * Each pinyin is corresponding to unihans of same\n     * offset in the unihans array.\n     */\n    public static final byte[][] PINYINS = {\n            {65, 0, 0, 0, 0, 0}, {65, 73, 0, 0, 0, 0},\n            {65, 78, 0, 0, 0, 0}, {65, 78, 71, 0, 0, 0},\n            {65, 79, 0, 0, 0, 0}, {66, 65, 0, 0, 0, 0},\n            {66, 65, 73, 0, 0, 0}, {66, 65, 78, 0, 0, 0},\n            {66, 65, 78, 71, 0, 0}, {66, 65, 79, 0, 0, 0},\n            {66, 69, 73, 0, 0, 0}, {66, 69, 78, 0, 0, 0},\n            {66, 69, 78, 71, 0, 0}, {66, 73, 0, 0, 0, 0},\n            {66, 73, 65, 78, 0, 0}, {66, 73, 65, 79, 0, 0},\n            {66, 73, 69, 0, 0, 0}, {66, 73, 78, 0, 0, 0},\n            {66, 73, 78, 71, 0, 0}, {66, 79, 0, 0, 0, 0},\n            {66, 85, 0, 0, 0, 0}, {67, 65, 0, 0, 0, 0},\n            {67, 65, 73, 0, 0, 0}, {67, 65, 78, 0, 0, 0},\n            {67, 65, 78, 71, 0, 0}, {67, 65, 79, 0, 0, 0},\n            {67, 69, 0, 0, 0, 0}, {67, 69, 78, 0, 0, 0},\n            {67, 69, 78, 71, 0, 0}, {90, 69, 78, 71, 0, 0},\n            {67, 69, 78, 71, 0, 0}, {67, 72, 65, 0, 0, 0},\n            {67, 72, 65, 73, 0, 0}, {67, 72, 65, 78, 0, 0},\n            {67, 72, 65, 78, 71, 0}, {67, 72, 65, 79, 0, 0},\n            {67, 72, 69, 0, 0, 0}, {67, 72, 69, 78, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {67, 72, 69, 78, 0, 0},\n            {67, 72, 69, 78, 71, 0}, {67, 72, 73, 0, 0, 0},\n            {67, 72, 79, 78, 71, 0}, {67, 72, 79, 85, 0, 0},\n            {67, 72, 85, 0, 0, 0}, {67, 72, 85, 65, 0, 0},\n            {67, 72, 85, 65, 73, 0}, {67, 72, 85, 65, 78, 0},\n            {67, 72, 85, 65, 78, 71}, {67, 72, 85, 73, 0, 0},\n            {67, 72, 85, 78, 0, 0}, {67, 72, 85, 79, 0, 0},\n            {67, 73, 0, 0, 0, 0}, {67, 79, 78, 71, 0, 0},\n            {67, 79, 85, 0, 0, 0}, {67, 85, 0, 0, 0, 0},\n            {67, 85, 65, 78, 0, 0}, {67, 85, 73, 0, 0, 0},\n            {67, 85, 78, 0, 0, 0}, {67, 85, 79, 0, 0, 0},\n            {68, 65, 0, 0, 0, 0}, {68, 65, 73, 0, 0, 0},\n            {68, 65, 78, 0, 0, 0}, {68, 65, 78, 71, 0, 0},\n            {68, 65, 79, 0, 0, 0}, {68, 69, 0, 0, 0, 0},\n            {68, 69, 78, 0, 0, 0}, {68, 69, 78, 71, 0, 0},\n            {68, 73, 0, 0, 0, 0}, {68, 73, 65, 0, 0, 0},\n            {68, 73, 65, 78, 0, 0}, {68, 73, 65, 79, 0, 0},\n            {68, 73, 69, 0, 0, 0}, {68, 73, 78, 71, 0, 0},\n            {68, 73, 85, 0, 0, 0}, {68, 79, 78, 71, 0, 0},\n            {68, 79, 85, 0, 0, 0}, {68, 85, 0, 0, 0, 0},\n            {68, 85, 65, 78, 0, 0}, {68, 85, 73, 0, 0, 0},\n            {68, 85, 78, 0, 0, 0}, {68, 85, 79, 0, 0, 0},\n            {69, 0, 0, 0, 0, 0}, {69, 73, 0, 0, 0, 0},\n            {69, 78, 0, 0, 0, 0}, {69, 78, 71, 0, 0, 0},\n            {69, 82, 0, 0, 0, 0}, {70, 65, 0, 0, 0, 0},\n            {70, 65, 78, 0, 0, 0}, {70, 65, 78, 71, 0, 0},\n            {70, 69, 73, 0, 0, 0}, {70, 69, 78, 0, 0, 0},\n            {70, 69, 78, 71, 0, 0}, {70, 73, 65, 79, 0, 0},\n            {70, 79, 0, 0, 0, 0}, {70, 79, 85, 0, 0, 0},\n            {70, 85, 0, 0, 0, 0}, {71, 65, 0, 0, 0, 0},\n            {71, 65, 73, 0, 0, 0}, {71, 65, 78, 0, 0, 0},\n            {71, 65, 78, 71, 0, 0}, {71, 65, 79, 0, 0, 0},\n            {71, 69, 0, 0, 0, 0}, {71, 69, 73, 0, 0, 0},\n            {71, 69, 78, 0, 0, 0}, {71, 69, 78, 71, 0, 0},\n            {71, 79, 78, 71, 0, 0}, {71, 79, 85, 0, 0, 0},\n            {71, 85, 0, 0, 0, 0}, {71, 85, 65, 0, 0, 0},\n            {71, 85, 65, 73, 0, 0}, {71, 85, 65, 78, 0, 0},\n            {71, 85, 65, 78, 71, 0}, {71, 85, 73, 0, 0, 0},\n            {71, 85, 78, 0, 0, 0}, {71, 85, 79, 0, 0, 0},\n            {72, 65, 0, 0, 0, 0}, {72, 65, 73, 0, 0, 0},\n            {72, 65, 78, 0, 0, 0}, {72, 65, 78, 71, 0, 0},\n            {72, 65, 79, 0, 0, 0}, {72, 69, 0, 0, 0, 0},\n            {72, 69, 73, 0, 0, 0}, {72, 69, 78, 0, 0, 0},\n            {72, 69, 78, 71, 0, 0}, {72, 77, 0, 0, 0, 0},\n            {72, 79, 78, 71, 0, 0}, {72, 79, 85, 0, 0, 0},\n            {72, 85, 0, 0, 0, 0}, {72, 85, 65, 0, 0, 0},\n            {72, 85, 65, 73, 0, 0}, {72, 85, 65, 78, 0, 0},\n            {72, 85, 65, 78, 71, 0}, {72, 85, 73, 0, 0, 0},\n            {72, 85, 78, 0, 0, 0}, {72, 85, 79, 0, 0, 0},\n            {74, 73, 0, 0, 0, 0}, {74, 73, 65, 0, 0, 0},\n            {74, 73, 65, 78, 0, 0}, {74, 73, 65, 78, 71, 0},\n            {74, 73, 65, 79, 0, 0}, {74, 73, 69, 0, 0, 0},\n            {74, 73, 78, 0, 0, 0}, {74, 73, 78, 71, 0, 0},\n            {74, 73, 79, 78, 71, 0}, {74, 73, 85, 0, 0, 0},\n            {74, 85, 0, 0, 0, 0}, {74, 85, 65, 78, 0, 0},\n            {74, 85, 69, 0, 0, 0}, {74, 85, 78, 0, 0, 0},\n            {75, 65, 0, 0, 0, 0}, {75, 65, 73, 0, 0, 0},\n            {75, 65, 78, 0, 0, 0}, {75, 65, 78, 71, 0, 0},\n            {75, 65, 79, 0, 0, 0}, {75, 69, 0, 0, 0, 0},\n            {75, 69, 78, 0, 0, 0}, {75, 69, 78, 71, 0, 0},\n            {75, 79, 78, 71, 0, 0}, {75, 79, 85, 0, 0, 0},\n            {75, 85, 0, 0, 0, 0}, {75, 85, 65, 0, 0, 0},\n            {75, 85, 65, 73, 0, 0}, {75, 85, 65, 78, 0, 0},\n            {75, 85, 65, 78, 71, 0}, {75, 85, 73, 0, 0, 0},\n            {75, 85, 78, 0, 0, 0}, {75, 85, 79, 0, 0, 0},\n            {76, 65, 0, 0, 0, 0}, {76, 65, 73, 0, 0, 0},\n            {76, 65, 78, 0, 0, 0}, {76, 65, 78, 71, 0, 0},\n            {76, 65, 79, 0, 0, 0}, {76, 69, 0, 0, 0, 0},\n            {76, 69, 73, 0, 0, 0}, {76, 69, 78, 71, 0, 0},\n            {76, 73, 0, 0, 0, 0}, {76, 73, 65, 0, 0, 0},\n            {76, 73, 65, 78, 0, 0}, {76, 73, 65, 78, 71, 0},\n            {76, 73, 65, 79, 0, 0}, {76, 73, 69, 0, 0, 0},\n            {76, 73, 78, 0, 0, 0}, {76, 73, 78, 71, 0, 0},\n            {76, 73, 85, 0, 0, 0}, {76, 79, 0, 0, 0, 0},\n            {76, 79, 78, 71, 0, 0}, {76, 79, 85, 0, 0, 0},\n            {76, 85, 0, 0, 0, 0}, {76, 85, 65, 78, 0, 0},\n            {76, 85, 69, 0, 0, 0}, {76, 85, 78, 0, 0, 0},\n            {76, 85, 79, 0, 0, 0}, {77, 0, 0, 0, 0, 0},\n            {77, 65, 0, 0, 0, 0}, {77, 65, 73, 0, 0, 0},\n            {77, 65, 78, 0, 0, 0}, {77, 65, 78, 71, 0, 0},\n            {77, 65, 79, 0, 0, 0}, {77, 69, 0, 0, 0, 0},\n            {77, 69, 73, 0, 0, 0}, {77, 69, 78, 0, 0, 0},\n            {77, 69, 78, 71, 0, 0}, {77, 73, 0, 0, 0, 0},\n            {77, 73, 65, 78, 0, 0}, {77, 73, 65, 79, 0, 0},\n            {77, 73, 69, 0, 0, 0}, {77, 73, 78, 0, 0, 0},\n            {77, 73, 78, 71, 0, 0}, {77, 73, 85, 0, 0, 0},\n            {77, 79, 0, 0, 0, 0}, {77, 79, 85, 0, 0, 0},\n            {77, 85, 0, 0, 0, 0}, {78, 0, 0, 0, 0, 0},\n            {78, 65, 0, 0, 0, 0}, {78, 65, 73, 0, 0, 0},\n            {78, 65, 78, 0, 0, 0}, {78, 65, 78, 71, 0, 0},\n            {78, 65, 79, 0, 0, 0}, {78, 69, 0, 0, 0, 0},\n            {78, 69, 73, 0, 0, 0}, {78, 69, 78, 0, 0, 0},\n            {78, 69, 78, 71, 0, 0}, {78, 73, 0, 0, 0, 0},\n            {78, 73, 65, 78, 0, 0}, {78, 73, 65, 78, 71, 0},\n            {78, 73, 65, 79, 0, 0}, {78, 73, 69, 0, 0, 0},\n            {78, 73, 78, 0, 0, 0}, {78, 73, 78, 71, 0, 0},\n            {78, 73, 85, 0, 0, 0}, {78, 79, 78, 71, 0, 0},\n            {78, 79, 85, 0, 0, 0}, {78, 85, 0, 0, 0, 0},\n            {78, 85, 65, 78, 0, 0}, {78, 85, 69, 0, 0, 0},\n            {78, 85, 78, 0, 0, 0}, {78, 85, 79, 0, 0, 0},\n            {79, 0, 0, 0, 0, 0}, {79, 85, 0, 0, 0, 0},\n            {80, 65, 0, 0, 0, 0}, {80, 65, 73, 0, 0, 0},\n            {80, 65, 78, 0, 0, 0}, {80, 65, 78, 71, 0, 0},\n            {80, 65, 79, 0, 0, 0}, {80, 69, 73, 0, 0, 0},\n            {80, 69, 78, 0, 0, 0}, {80, 69, 78, 71, 0, 0},\n            {80, 73, 0, 0, 0, 0}, {80, 73, 65, 78, 0, 0},\n            {80, 73, 65, 79, 0, 0}, {80, 73, 69, 0, 0, 0},\n            {80, 73, 78, 0, 0, 0}, {80, 73, 78, 71, 0, 0},\n            {80, 79, 0, 0, 0, 0}, {80, 79, 85, 0, 0, 0},\n            {80, 85, 0, 0, 0, 0}, {81, 73, 0, 0, 0, 0},\n            {81, 73, 65, 0, 0, 0}, {81, 73, 65, 78, 0, 0},\n            {81, 73, 65, 78, 71, 0}, {81, 73, 65, 79, 0, 0},\n            {81, 73, 69, 0, 0, 0}, {81, 73, 78, 0, 0, 0},\n            {81, 73, 78, 71, 0, 0}, {81, 73, 79, 78, 71, 0},\n            {81, 73, 85, 0, 0, 0}, {81, 85, 0, 0, 0, 0},\n            {81, 85, 65, 78, 0, 0}, {81, 85, 69, 0, 0, 0},\n            {81, 85, 78, 0, 0, 0}, {82, 65, 78, 0, 0, 0},\n            {82, 65, 78, 71, 0, 0}, {82, 65, 79, 0, 0, 0},\n            {82, 69, 0, 0, 0, 0}, {82, 69, 78, 0, 0, 0},\n            {82, 69, 78, 71, 0, 0}, {82, 73, 0, 0, 0, 0},\n            {82, 79, 78, 71, 0, 0}, {82, 79, 85, 0, 0, 0},\n            {82, 85, 0, 0, 0, 0}, {82, 85, 65, 0, 0, 0},\n            {82, 85, 65, 78, 0, 0}, {82, 85, 73, 0, 0, 0},\n            {82, 85, 78, 0, 0, 0}, {82, 85, 79, 0, 0, 0},\n            {83, 65, 0, 0, 0, 0}, {83, 65, 73, 0, 0, 0},\n            {83, 65, 78, 0, 0, 0}, {83, 65, 78, 71, 0, 0},\n            {83, 65, 79, 0, 0, 0}, {83, 69, 0, 0, 0, 0},\n            {83, 69, 78, 0, 0, 0}, {83, 69, 78, 71, 0, 0},\n            {83, 72, 65, 0, 0, 0}, {83, 72, 65, 73, 0, 0},\n            {83, 72, 65, 78, 0, 0}, {83, 72, 65, 78, 71, 0},\n            {83, 72, 65, 79, 0, 0}, {83, 72, 69, 0, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {88, 73, 78, 0, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {83, 72, 69, 78, 71, 0},\n            {83, 72, 73, 0, 0, 0}, {83, 72, 79, 85, 0, 0},\n            {83, 72, 85, 0, 0, 0}, {83, 72, 85, 65, 0, 0},\n            {83, 72, 85, 65, 73, 0}, {83, 72, 85, 65, 78, 0},\n            {83, 72, 85, 65, 78, 71}, {83, 72, 85, 73, 0, 0},\n            {83, 72, 85, 78, 0, 0}, {83, 72, 85, 79, 0, 0},\n            {83, 73, 0, 0, 0, 0}, {83, 79, 78, 71, 0, 0},\n            {83, 79, 85, 0, 0, 0}, {83, 85, 0, 0, 0, 0},\n            {83, 85, 65, 78, 0, 0}, {83, 85, 73, 0, 0, 0},\n            {83, 85, 78, 0, 0, 0}, {83, 85, 79, 0, 0, 0},\n            {84, 65, 0, 0, 0, 0}, {84, 65, 73, 0, 0, 0},\n            {84, 65, 78, 0, 0, 0}, {84, 65, 78, 71, 0, 0},\n            {84, 65, 79, 0, 0, 0}, {84, 69, 0, 0, 0, 0},\n            {84, 69, 78, 71, 0, 0}, {84, 73, 0, 0, 0, 0},\n            {84, 73, 65, 78, 0, 0}, {84, 73, 65, 79, 0, 0},\n            {84, 73, 69, 0, 0, 0}, {84, 73, 78, 71, 0, 0},\n            {84, 79, 78, 71, 0, 0}, {84, 79, 85, 0, 0, 0},\n            {84, 85, 0, 0, 0, 0}, {84, 85, 65, 78, 0, 0},\n            {84, 85, 73, 0, 0, 0}, {84, 85, 78, 0, 0, 0},\n            {84, 85, 79, 0, 0, 0}, {87, 65, 0, 0, 0, 0},\n            {87, 65, 73, 0, 0, 0}, {87, 65, 78, 0, 0, 0},\n            {87, 65, 78, 71, 0, 0}, {87, 69, 73, 0, 0, 0},\n            {87, 69, 78, 0, 0, 0}, {87, 69, 78, 71, 0, 0},\n            {87, 79, 0, 0, 0, 0}, {87, 85, 0, 0, 0, 0},\n            {88, 73, 0, 0, 0, 0}, {88, 73, 65, 0, 0, 0},\n            {88, 73, 65, 78, 0, 0}, {88, 73, 65, 78, 71, 0},\n            {88, 73, 65, 79, 0, 0}, {88, 73, 69, 0, 0, 0},\n            {88, 73, 78, 0, 0, 0}, {88, 73, 78, 71, 0, 0},\n            {88, 73, 79, 78, 71, 0}, {88, 73, 85, 0, 0, 0},\n            {88, 85, 0, 0, 0, 0}, {88, 85, 65, 78, 0, 0},\n            {88, 85, 69, 0, 0, 0}, {88, 85, 78, 0, 0, 0},\n            {89, 65, 0, 0, 0, 0}, {89, 65, 78, 0, 0, 0},\n            {89, 65, 78, 71, 0, 0}, {89, 65, 79, 0, 0, 0},\n            {89, 69, 0, 0, 0, 0}, {89, 73, 0, 0, 0, 0},\n            {89, 73, 78, 0, 0, 0}, {89, 73, 78, 71, 0, 0},\n            {89, 79, 0, 0, 0, 0}, {89, 79, 78, 71, 0, 0},\n            {89, 79, 85, 0, 0, 0}, {89, 85, 0, 0, 0, 0},\n            {89, 85, 65, 78, 0, 0}, {89, 85, 69, 0, 0, 0},\n            {89, 85, 78, 0, 0, 0}, {74, 85, 78, 0, 0, 0},\n            {89, 85, 78, 0, 0, 0}, {90, 65, 0, 0, 0, 0},\n            {90, 65, 73, 0, 0, 0}, {90, 65, 78, 0, 0, 0},\n            {90, 65, 78, 71, 0, 0}, {90, 65, 79, 0, 0, 0},\n            {90, 69, 0, 0, 0, 0}, {90, 69, 73, 0, 0, 0},\n            {90, 69, 78, 0, 0, 0}, {90, 69, 78, 71, 0, 0},\n            {90, 72, 65, 0, 0, 0}, {90, 72, 65, 73, 0, 0},\n            {90, 72, 65, 78, 0, 0}, {90, 72, 65, 78, 71, 0},\n            {67, 72, 65, 78, 71, 0}, {90, 72, 65, 78, 71, 0},\n            {90, 72, 65, 79, 0, 0}, {90, 72, 69, 0, 0, 0},\n            {90, 72, 69, 78, 0, 0}, {90, 72, 69, 78, 71, 0},\n            {90, 72, 73, 0, 0, 0}, {83, 72, 73, 0, 0, 0},\n            {90, 72, 73, 0, 0, 0}, {90, 72, 79, 78, 71, 0},\n            {90, 72, 79, 85, 0, 0}, {90, 72, 85, 0, 0, 0},\n            {90, 72, 85, 65, 0, 0}, {90, 72, 85, 65, 73, 0},\n            {90, 72, 85, 65, 78, 0}, {90, 72, 85, 65, 78, 71},\n            {90, 72, 85, 73, 0, 0}, {90, 72, 85, 78, 0, 0},\n            {90, 72, 85, 79, 0, 0}, {90, 73, 0, 0, 0, 0},\n            {90, 79, 78, 71, 0, 0}, {90, 79, 85, 0, 0, 0},\n            {90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0},\n            {90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0},\n            {90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0},\n            {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},};\n\n    /**\n     * First and last Chinese character with known Pinyin according to zh collation\n     */\n    private static final String FIRST_PINYIN_UNIHAN = \"\\u963F\";\n    private static final String LAST_PINYIN_UNIHAN = \"\\u9FFF\";\n\n    private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);\n\n    private static HanziToPinyin sInstance;\n    private final boolean mHasChinaCollator;\n\n    public static class Token {\n        /**\n         * Separator between target string for each source char\n         */\n        public static final String SEPARATOR = \" \";\n\n        public static final int LATIN = 1;\n        public static final int PINYIN = 2;\n        public static final int UNKNOWN = 3;\n\n        public Token() {\n        }\n\n        public Token(int type, String source, String target) {\n            this.type = type;\n            this.source = source;\n            this.target = target;\n        }\n\n        /**\n         * Type of this token, ASCII, PINYIN or UNKNOWN.\n         */\n        public int type;\n        /**\n         * Original string before translation.\n         */\n        public String source;\n        /**\n         * Translated string of source. For Han, target is corresponding Pinyin. Otherwise target is\n         * original string in source.\n         */\n        public String target;\n    }\n\n    protected HanziToPinyin(boolean hasChinaCollator) {\n        mHasChinaCollator = hasChinaCollator;\n    }\n\n    public static HanziToPinyin getInstance() {\n        synchronized (HanziToPinyin.class) {\n            if (sInstance != null) {\n                return sInstance;\n            }\n            // Check if zh_CN collation data is available\n            final Locale locale[] = Collator.getAvailableLocales();\n            for (int i = 0; i < locale.length; i++) {\n                if (locale[i].equals(Locale.CHINA) || locale[i].getLanguage().contains(\"zh\")) {\n                    // Do self validation just once.\n                    if (DEBUG) {\n                        Log.d(TAG, \"Self validation. Result: \" + doSelfValidation());\n                    }\n                    sInstance = new HanziToPinyin(true);\n                    return sInstance;\n                }\n            }\n            if (sInstance == null){//这个判断是用于处理国产ROM的兼容性问题\n                if (Locale.CHINA.equals(Locale.getDefault())){\n                    sInstance = new HanziToPinyin(true);\n                    return sInstance;\n                }\n            }\n            Log.w(TAG, \"There is no Chinese collator, HanziToPinyin is disabled\");\n            sInstance = new HanziToPinyin(false);\n            return sInstance;\n        }\n    }\n\n    /**\n     * Validate if our internal table has some wrong value.\n     *\n     * @return true when the table looks correct.\n     */\n    private static boolean doSelfValidation() {\n        char lastChar = UNIHANS[0];\n        String lastString = Character.toString(lastChar);\n        for (char c : UNIHANS) {\n            if (lastChar == c) {\n                continue;\n            }\n            final String curString = Character.toString(c);\n            int cmp = COLLATOR.compare(lastString, curString);\n            if (cmp >= 0) {\n                Log.e(TAG, \"Internal error in Unihan table. \" + \"The last string \\\"\" + lastString\n                        + \"\\\" is greater than current string \\\"\" + curString + \"\\\".\");\n                return false;\n            }\n            lastString = curString;\n        }\n        return true;\n    }\n\n    private Token getToken(char character) {\n        Token token = new Token();\n        final String letter = Character.toString(character);\n        token.source = letter;\n        int offset = -1;\n        int cmp;\n        if (character < 256) {\n            token.type = Token.LATIN;\n            token.target = letter;\n            return token;\n        } else {\n            cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);\n            if (cmp < 0) {\n                token.type = Token.UNKNOWN;\n                token.target = letter;\n                return token;\n            } else if (cmp == 0) {\n                token.type = Token.PINYIN;\n                offset = 0;\n            } else {\n                cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);\n                if (cmp > 0) {\n                    token.type = Token.UNKNOWN;\n                    token.target = letter;\n                    return token;\n                } else if (cmp == 0) {\n                    token.type = Token.PINYIN;\n                    offset = UNIHANS.length - 1;\n                }\n            }\n        }\n\n        token.type = Token.PINYIN;\n        if (offset < 0) {\n            int begin = 0;\n            int end = UNIHANS.length - 1;\n            while (begin <= end) {\n                offset = (begin + end) / 2;\n                final String unihan = Character.toString(UNIHANS[offset]);\n                cmp = COLLATOR.compare(letter, unihan);\n                if (cmp == 0) {\n                    break;\n                } else if (cmp > 0) {\n                    begin = offset + 1;\n                } else {\n                    end = offset - 1;\n                }\n            }\n        }\n        if (cmp < 0) {\n            offset--;\n        }\n        StringBuilder pinyin = new StringBuilder();\n        for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) {\n            pinyin.append((char) PINYINS[offset][j]);\n        }\n        token.target = pinyin.toString();\n        if (TextUtils.isEmpty(token.target)) {\n            token.type = Token.UNKNOWN;\n            token.target = token.source;\n        }\n        return token;\n    }\n\n    /**\n     * Convert the input to a array of tokens. The sequence of ASCII or Unknown characters without\n     * space will be put into a Token, One Hanzi character which has pinyin will be treated as a\n     * Token. If these is no China collator, the empty token array is returned.\n     */\n    public ArrayList<Token> get(final String input) {\n        ArrayList<Token> tokens = new ArrayList<Token>();\n        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {\n            // return empty tokens.\n            return tokens;\n        }\n        final int inputLength = input.length();\n        final StringBuilder sb = new StringBuilder();\n        int tokenType = Token.LATIN;\n        // Go through the input, create a new token when\n        // a. Token type changed\n        // b. Get the Pinyin of current charater.\n        // c. current character is space.\n        for (int i = 0; i < inputLength; i++) {\n            final char character = input.charAt(i);\n            if (character == ' ') {\n                if (sb.length() > 0) {\n                    addToken(sb, tokens, tokenType);\n                }\n            } else if (character < 256) {\n                if (tokenType != Token.LATIN && sb.length() > 0) {\n                    addToken(sb, tokens, tokenType);\n                }\n                tokenType = Token.LATIN;\n                sb.append(character);\n            } else {\n                Token t = getToken(character);\n                if (t.type == Token.PINYIN) {\n                    if (sb.length() > 0) {\n                        addToken(sb, tokens, tokenType);\n                    }\n                    tokens.add(t);\n                    tokenType = Token.PINYIN;\n                } else {\n                    if (tokenType != t.type && sb.length() > 0) {\n                        addToken(sb, tokens, tokenType);\n                    }\n                    tokenType = t.type;\n                    sb.append(character);\n                }\n            }\n        }\n        if (sb.length() > 0) {\n            addToken(sb, tokens, tokenType);\n        }\n        return tokens;\n    }\n\n    private void addToken(\n            final StringBuilder sb, final ArrayList<Token> tokens, final int tokenType) {\n        String str = sb.toString();\n        tokens.add(new Token(tokenType, str, str));\n        sb.setLength(0);\n    }\n\n    public String toPinyinString(String string) {\n        if (string == null) {\n            return null;\n        }\n        StringBuilder sb = new StringBuilder();\n        ArrayList<Token> tokens = get(string);\n        for (Token token : tokens) {\n            sb.append(token.target);\n        }\n        return sb.toString().toLowerCase();\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/utils/Misc.java",
    "content": "package io.virtualapp.utils;\n\nimport android.app.Activity;\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.support.v7.app.AlertDialog;\nimport android.widget.Toast;\n\nimport io.virtualapp.R;\nimport moe.feng.alipay.zerosdk.AlipayZeroSdk;\n\n/**\n * @author weishu\n * @date 2018/10/29.\n */\npublic class Misc {\n    public static void showDonate(Activity context) {\n        final String alipay = context.getResources().getString(R.string.donate_alipay);\n        final String[] items = {alipay, \"PayPal\", \"Bitcoin\"};\n\n        AlertDialog chooseDialog = new AlertDialog.Builder(context, R.style.Theme_AppCompat_DayNight_Dialog_Alert)\n                .setTitle(R.string.donate_choose_title)\n                .setItems(items, (dialog1, which1) -> {\n                    dialog1.dismiss();\n                    if (which1 == 0) {\n                        if (!AlipayZeroSdk.hasInstalledAlipayClient(context)) {\n                            Toast.makeText(context, R.string.prompt_alipay_not_found, Toast.LENGTH_SHORT).show();\n                            return;\n                        }\n                        AlipayZeroSdk.startAlipayClient(context, \"FKX016770URBZGZSR37U37\");\n                    } else if (which1 == 1) {\n                        try {\n                            Intent t = new Intent(Intent.ACTION_VIEW);\n                            t.setData(Uri.parse(\"https://paypal.me/virtualxposed\"));\n                            context.startActivity(t);\n                        } catch (Throwable ignored) {\n                            ignored.printStackTrace();\n                        }\n                    } else if (which1 == 2) {\n                        final String address = \"39Wst8oL74pRP2vKPkPihH6RFQF4hWoBqU\";\n\n                        try {\n                            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n                            if (clipboardManager != null) {\n                                clipboardManager.setPrimaryClip(ClipData.newPlainText(null, address));\n                            }\n                            Toast.makeText(context, context.getResources().getString(R.string.donate_bitconins_tips), Toast.LENGTH_SHORT).show();\n                        } catch (Throwable ignored) {\n                            ignored.printStackTrace();\n                        }\n                    }\n                })\n                .create();\n        chooseDialog.show();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/BaseView.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.LinearInterpolator;\n\npublic abstract class BaseView extends View {\n\n\n    public ValueAnimator valueAnimator;\n\n    public BaseView(Context context) {\n        this(context, null);\n    }\n\n    public BaseView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public BaseView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        InitPaint();\n    }\n\n    public void startAnim() {\n        stopAnim();\n        startViewAnim(0f, 1f, 1250);\n    }\n\n    public void startAnim(int time) {\n        stopAnim();\n        startViewAnim(0f, 1f, time);\n    }\n\n    public void stopAnim() {\n        if (valueAnimator != null) {\n            clearAnimation();\n\n            valueAnimator.setRepeatCount(0);\n            valueAnimator.cancel();\n            valueAnimator.end();\n            if (OnStopAnim() == 0) {\n                valueAnimator.setRepeatCount(0);\n                valueAnimator.cancel();\n                valueAnimator.end();\n            }\n\n        }\n    }\n\n    private ValueAnimator startViewAnim(float startF, final float endF, long time) {\n        valueAnimator = ValueAnimator.ofFloat(startF, endF);\n        valueAnimator.setDuration(time);\n        valueAnimator.setInterpolator(new LinearInterpolator());\n\n\n        valueAnimator.setRepeatCount(SetAnimRepeatCount());\n\n\n        if (ValueAnimator.RESTART == SetAnimRepeatMode()) {\n            valueAnimator.setRepeatMode(ValueAnimator.RESTART);\n\n        } else if (ValueAnimator.REVERSE == SetAnimRepeatMode()) {\n            valueAnimator.setRepeatMode(ValueAnimator.REVERSE);\n\n        }\n\n        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator valueAnimator) {\n                OnAnimationUpdate(valueAnimator);\n\n            }\n        });\n        valueAnimator.addListener(new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationEnd(Animator animation) {\n                super.onAnimationEnd(animation);\n\n            }\n\n            @Override\n            public void onAnimationStart(Animator animation) {\n\n                super.onAnimationStart(animation);\n            }\n\n            @Override\n            public void onAnimationRepeat(Animator animation) {\n                super.onAnimationRepeat(animation);\n                OnAnimationRepeat(animation);\n            }\n        });\n        if (!valueAnimator.isRunning()) {\n            AnimIsRunning();\n            valueAnimator.start();\n\n        }\n\n        return valueAnimator;\n    }\n\n\n    protected abstract void InitPaint();\n\n    protected abstract void OnAnimationUpdate(ValueAnimator valueAnimator);\n\n    protected abstract void OnAnimationRepeat(Animator animation);\n\n    protected abstract int OnStopAnim();\n\n    protected abstract int SetAnimRepeatMode();\n\n    protected abstract int SetAnimRepeatCount();\n\n    protected abstract void AnimIsRunning();\n\n\n    public float getFontlength(Paint paint, String str) {\n        Rect rect = new Rect();\n        paint.getTextBounds(str, 0, str.length(), rect);\n        return rect.width();\n    }\n\n    public float getFontHeight(Paint paint, String str) {\n        Rect rect = new Rect();\n        paint.getTextBounds(str, 0, str.length(), rect);\n        return rect.height();\n\n    }\n\n    public float getFontHeight(Paint paint) {\n        Paint.FontMetrics fm = paint.getFontMetrics();\n        return fm.descent - fm.ascent;\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/CardStackAdapter.java",
    "content": "package io.virtualapp.widgets;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.animation.AnimatorSet;\nimport android.animation.ObjectAnimator;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.util.DisplayMetrics;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.DecelerateInterpolator;\nimport android.widget.FrameLayout;\n\nimport io.virtualapp.R;\n\n/**\n * This class acts as an adapter for the {@link CardStackLayout} view. This\n * adapter is intentionally made an abstract class with following abstract\n * methods -\n * <p>\n * <p>\n * {@link #getCount()} - Decides the number of views present in the view\n * <p>\n * {@link #createView(int, ViewGroup)} - Creates the view for all positions in\n * range [0, {@link #getCount()})\n * <p>\n * Contains the logic for touch events in {@link #onTouch(View, MotionEvent)}\n */\npublic abstract class CardStackAdapter implements View.OnTouchListener, View.OnClickListener {\n\n\tpublic static final int ANIM_DURATION = 600;\n\tpublic static final int DECELERATION_FACTOR = 2;\n\n\tpublic static final int INVALID_CARD_POSITION = -1;\n\tprivate final int mScreenHeight;\n\tprivate final int dp30;\n\t// Settings for the adapter from layout\n\tprivate float mCardGapBottom;\n\tprivate float mCardGap;\n\tprivate int mParallaxScale;\n\tprivate boolean mParallaxEnabled;\n\tprivate boolean mShowInitAnimation;\n\tprivate int fullCardHeight;\n\tprivate View[] mCardViews;\n\tprivate float dp8;\n\tprivate CardStackLayout mParent;\n\n\tprivate boolean mScreenTouchable = false;\n\tprivate float mTouchFirstY = -1;\n\tprivate float mTouchPrevY = -1;\n\tprivate float mTouchDistance = 0;\n\tprivate int mSelectedCardPosition = INVALID_CARD_POSITION;\n\tprivate float scaleFactorForElasticEffect;\n\tprivate int mParentPaddingTop = 0;\n\tprivate int mCardPaddingInternal = 0;\n\n\tpublic CardStackAdapter(Context context) {\n\t\tResources resources = context.getResources();\n\n\t\tDisplayMetrics dm = Resources.getSystem().getDisplayMetrics();\n\t\tmScreenHeight = dm.heightPixels;\n\t\tdp30 = (int) resources.getDimension(R.dimen.dp30);\n\t\tscaleFactorForElasticEffect = (int) resources.getDimension(R.dimen.dp8);\n\t\tdp8 = (int) resources.getDimension(R.dimen.dp8);\n\t}\n\n\tprotected float getCardGapBottom() {\n\t\treturn mCardGapBottom;\n\t}\n\n\t/**\n\t * Defines and initializes the view to be shown in the\n\t * {@link CardStackLayout} Provides two parameters to the sub-class namely -\n\t *\n\t * @param position\n\t * @param container\n\t * @return View corresponding to the position and parent container\n\t */\n\tpublic abstract View createView(int position, ViewGroup container);\n\n\t/**\n\t * Defines the number of cards that are present in the\n\t * {@link CardStackLayout}\n\t *\n\t * @return cardCount - Number of views in the related\n\t *         {@link CardStackLayout}\n\t */\n\tpublic abstract int getCount();\n\n\t/**\n\t * Returns true if no animation is in progress currently. Can be used to\n\t * disable any events if they are not allowed during an animation. Returns\n\t * false if an animation is in progress.\n\t *\n\t * @return - true if animation in progress, false otherwise\n\t */\n\tpublic boolean isScreenTouchable() {\n\t\treturn mScreenTouchable;\n\t}\n\n\tprivate void setScreenTouchable(boolean screenTouchable) {\n\t\tthis.mScreenTouchable = screenTouchable;\n\t}\n\n\tvoid addView(final int position) {\n\t\tView root = createView(position, mParent);\n\t\troot.setOnTouchListener(this);\n\t\troot.setTag(R.id.cardstack_internal_position_tag, position);\n\t\troot.setLayerType(View.LAYER_TYPE_HARDWARE, null);\n\n\t\tmCardPaddingInternal = root.getPaddingTop();\n\n\t\tFrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, fullCardHeight);\n\t\troot.setLayoutParams(lp);\n\t\tif (mShowInitAnimation) {\n\t\t\troot.setY(getCardFinalY(position));\n\t\t\tsetScreenTouchable(false);\n\t\t} else {\n\t\t\troot.setY(getCardOriginalY(position) - mParentPaddingTop);\n\t\t\tsetScreenTouchable(true);\n\t\t}\n\n\t\tmCardViews[position] = root;\n\n\t\tmParent.addView(root);\n\t}\n\n\tprotected float getCardFinalY(int position) {\n\t\treturn mScreenHeight - dp30 - ((getCount() - position) * mCardGapBottom) - mCardPaddingInternal;\n\t}\n\n\tprotected float getCardOriginalY(int position) {\n\t\treturn mParentPaddingTop + mCardGap * position;\n\t}\n\n\t/**\n\t * Resets all cards in {@link CardStackLayout} to their initial positions\n\t *\n\t * @param r\n\t *            Execute r.run() once the reset animation is done\n\t */\n\tpublic void resetCards(Runnable r) {\n\t\tList<Animator> animations = new ArrayList<>(getCount());\n\t\tfor (int i = 0; i < getCount(); i++) {\n\t\t\tfinal View child = mCardViews[i];\n\t\t\tanimations.add(ObjectAnimator.ofFloat(child, View.Y, (int) child.getY(), getCardOriginalY(i)));\n\t\t}\n\t\tstartAnimations(animations, r, true);\n\t}\n\n\t/**\n\t * Plays together all animations passed in as parameter. Once animation is\n\t * completed, r.run() is executed. If parameter isReset is set to true,\n\t * {@link #mSelectedCardPosition} is set to {@link #INVALID_CARD_POSITION}\n\t *\n\t * @param animations\n\t * @param r\n\t * @param isReset\n\t */\n\tprivate void startAnimations(List<Animator> animations, final Runnable r, final boolean isReset) {\n\t\tAnimatorSet animatorSet = new AnimatorSet();\n\t\tanimatorSet.playTogether(animations);\n\t\tanimatorSet.setDuration(ANIM_DURATION);\n\t\tanimatorSet.setInterpolator(new DecelerateInterpolator(DECELERATION_FACTOR));\n\t\tanimatorSet.addListener(new AnimatorListenerAdapter() {\n\t\t\t@Override\n\t\t\tpublic void onAnimationEnd(Animator animation) {\n\t\t\t\tif (r != null)\n\t\t\t\t\tr.run();\n\t\t\t\tsetScreenTouchable(true);\n\t\t\t\tif (isReset)\n\t\t\t\t\tmSelectedCardPosition = INVALID_CARD_POSITION;\n\t\t\t}\n\t\t});\n\t\tanimatorSet.start();\n\t}\n\n\t@Override\n\tpublic boolean onTouch(View v, MotionEvent event) {\n\t\tif (!isScreenTouchable()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfloat y = event.getRawY();\n\t\tint positionOfCardToMove = (int) v.getTag(R.id.cardstack_internal_position_tag);\n\n\t\tswitch (event.getAction()) {\n\t\t\tcase MotionEvent.ACTION_DOWN :\n\t\t\t\tif (mTouchFirstY != -1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tmTouchPrevY = mTouchFirstY = y;\n\t\t\t\tmTouchDistance = 0;\n\t\t\t\tbreak;\n\t\t\tcase MotionEvent.ACTION_MOVE :\n\t\t\t\tif (mSelectedCardPosition == INVALID_CARD_POSITION)\n\t\t\t\t\tmoveCards(positionOfCardToMove, y - mTouchFirstY);\n\t\t\t\tmTouchDistance += Math.abs(y - mTouchPrevY);\n\t\t\t\tbreak;\n\t\t\tcase MotionEvent.ACTION_CANCEL :\n\t\t\tcase MotionEvent.ACTION_UP :\n\t\t\t\tif (mTouchDistance < dp8 && Math.abs(y - mTouchFirstY) < dp8\n\t\t\t\t\t\t&& mSelectedCardPosition == INVALID_CARD_POSITION) {\n\t\t\t\t\tonClick(v);\n\t\t\t\t} else {\n\t\t\t\t\tresetCards();\n\t\t\t\t}\n\t\t\t\tmTouchPrevY = mTouchFirstY = -1;\n\t\t\t\tmTouchDistance = 0;\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void onClick(final View v) {\n\n\t\tif (!isScreenTouchable()) {\n\t\t\treturn;\n\t\t}\n\t\tsetScreenTouchable(false);\n\t\tif (mSelectedCardPosition == INVALID_CARD_POSITION) {\n\t\t\tmSelectedCardPosition = (int) v.getTag(R.id.cardstack_internal_position_tag);\n\n\t\t\tList<Animator> animations = new ArrayList<>(getCount());\n\t\t\tfor (int i = 0; i < getCount(); i++) {\n\t\t\t\tView child = mCardViews[i];\n\t\t\t\tanimations.add(getAnimatorForView(child, i, mSelectedCardPosition));\n\t\t\t}\n\t\t\tstartAnimations(animations, () -> {\n\t\t\t\tsetScreenTouchable(true);\n\t\t\t\tif (mParent.getOnCardSelectedListener() != null) {\n\t\t\t\t\tmParent.getOnCardSelectedListener().onCardSelected(v, mSelectedCardPosition);\n\t\t\t\t}\n\t\t\t}, false);\n\n\t\t}\n\t}\n\n\t/**\n\t * This method can be overridden to have different animations for each card\n\t * when a click event happens on any card view. This method will be called\n\t * for every\n\t *\n\t * @param view\n\t *            The view for which this method needs to return an animator\n\t * @param selectedCardPosition\n\t *            Position of the card that was clicked\n\t * @param currentCardPosition\n\t *            Position of the current card\n\t * @return animator which has to be applied on the current card\n\t */\n\tprotected Animator getAnimatorForView(View view, int currentCardPosition, int selectedCardPosition) {\n\t\tif (currentCardPosition != selectedCardPosition) {\n\t\t\treturn ObjectAnimator.ofFloat(view, View.Y, (int) view.getY(), getCardFinalY(currentCardPosition));\n\t\t} else {\n\t\t\treturn ObjectAnimator.ofFloat(view, View.Y, (int) view.getY(),\n\t\t\t\t\tgetCardOriginalY(0) + (currentCardPosition * mCardGapBottom));\n\t\t}\n\t}\n\n\tprivate void moveCards(int positionOfCardToMove, float diff) {\n\t\tif (diff < 0 || positionOfCardToMove < 0 || positionOfCardToMove >= getCount())\n\t\t\treturn;\n\t\tfor (int i = positionOfCardToMove; i < getCount(); i++) {\n\t\t\tfinal View child = mCardViews[i];\n\t\t\tfloat diffCard = diff / scaleFactorForElasticEffect;\n\t\t\tif (mParallaxEnabled) {\n\t\t\t\tif (mParallaxScale > 0) {\n\t\t\t\t\tdiffCard = diffCard * (mParallaxScale / 3) * (getCount() + 1 - i);\n\t\t\t\t} else {\n\t\t\t\t\tint scale = mParallaxScale * -1;\n\t\t\t\t\tdiffCard = diffCard * (i * (scale / 3) + 1);\n\t\t\t\t}\n\t\t\t} else\n\t\t\t\tdiffCard = diffCard * (getCount() * 2 + 1);\n\t\t\tchild.setY(getCardOriginalY(i) + diffCard);\n\t\t}\n\t}\n\n\t/**\n\t * Provides an API to {@link CardStackLayout} to set the parameters provided\n\t * to it in its XML\n\t *\n\t * @param cardStackLayout\n\t *            Parent of all cards\n\t */\n\tvoid setAdapterParams(CardStackLayout cardStackLayout) {\n\t\tmParent = cardStackLayout;\n\t\tmCardViews = new View[getCount()];\n\t\tmCardGapBottom = cardStackLayout.getCardGapBottom();\n\t\tmCardGap = cardStackLayout.getCardGap();\n\t\tmParallaxScale = cardStackLayout.getParallaxScale();\n\t\tmParallaxEnabled = cardStackLayout.isParallaxEnabled();\n\t\tif (mParallaxEnabled && mParallaxScale == 0)\n\t\t\tmParallaxEnabled = false;\n\t\tmShowInitAnimation = cardStackLayout.isShowInitAnimation();\n\t\tmParentPaddingTop = cardStackLayout.getPaddingTop();\n\t\tfullCardHeight = (int) (mScreenHeight - dp30 - dp8 - getCount() * mCardGapBottom);\n\t}\n\n\t/**\n\t * Resets all cards in {@link CardStackLayout} to their initial positions\n\t */\n\tpublic void resetCards() {\n\t\tresetCards(null);\n\t}\n\n\t/**\n\t * Returns false if all the cards are in their initial position i.e. no card\n\t * is selected\n\t * <p>\n\t * Returns true if the {@link CardStackLayout} has a card selected and all\n\t * other cards are at the bottom of the screen.\n\t *\n\t * @return true if any card is selected, false otherwise\n\t */\n\tpublic boolean isCardSelected() {\n\t\treturn mSelectedCardPosition != INVALID_CARD_POSITION;\n\t}\n\n\t/**\n\t * Returns the position of selected card. If no card is selected, returns\n\t * {@link #INVALID_CARD_POSITION}\n\t */\n\tpublic int getSelectedCardPosition() {\n\t\treturn mSelectedCardPosition;\n\t}\n\n\t/**\n\t * Since there is no view recycling in {@link CardStackLayout}, we maintain\n\t * an instance of every view that is set for every position. This method\n\t * returns a view at the requested position.\n\t *\n\t * @param position\n\t *            Position of card in {@link CardStackLayout}\n\t * @return View at requested position\n\t */\n\tpublic View getCardView(int position) {\n\t\tif (mCardViews == null)\n\t\t\treturn null;\n\n\t\treturn mCardViews[position];\n\t}\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/CardStackLayout.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.FrameLayout;\n\nimport io.virtualapp.R;\n\n/**\n * Displays a list of cards as a stack on the screen.\n * <p>\n * <b>XML attributes</b>\n * <p>\n * See {@link R.styleable#CardStackLayout CardStackLayout Attributes}\n * <p>\n * {@link R.styleable#CardStackLayout_showInitAnimation}\n * {@link R.styleable#CardStackLayout_card_gap}\n * {@link R.styleable#CardStackLayout_card_gap_bottom}\n * {@link R.styleable#CardStackLayout_parallax_enabled}\n * {@link R.styleable#CardStackLayout_parallax_scale}\n */\npublic class CardStackLayout extends FrameLayout {\n\tpublic static final boolean PARALLAX_ENABLED_DEFAULT = false;\n\tpublic static final boolean SHOW_INIT_ANIMATION_DEFAULT = true;\n\n\tprivate float mCardGapBottom;\n\tprivate float mCardGap;\n\tprivate boolean mShowInitAnimation;\n\tprivate boolean mParallaxEnabled;\n\tprivate int mParallaxScale;\n\tprivate OnCardSelected mOnCardSelectedListener = null;\n\n\tprivate CardStackAdapter mAdapter = null;\n\n\tpublic CardStackLayout(Context context) {\n\t\tsuper(context);\n\t\tresetDefaults();\n\t}\n\n\tpublic CardStackLayout(Context context, AttributeSet attrs) {\n\t\tthis(context, attrs, 0);\n\t}\n\n\tpublic CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n\t\tsuper(context, attrs, defStyleAttr);\n\t\thandleArgs(context, attrs, defStyleAttr, 0);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\tpublic CardStackLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n\t\tsuper(context, attrs, defStyleAttr, defStyleRes);\n\t\thandleArgs(context, attrs, defStyleAttr, defStyleRes);\n\t}\n\n\t/**\n\t * package restricted\n\t */\n\tOnCardSelected getOnCardSelectedListener() {\n\t\treturn mOnCardSelectedListener;\n\t}\n\n\t/**\n\t * Listen on card selection events for {@link CardStackLayout}. Sends\n\t * clicked view and it's corresponding position in the callback.\n\t *\n\t * @param onCardSelectedListener\n\t *            listener\n\t */\n\tpublic void setOnCardSelectedListener(OnCardSelected onCardSelectedListener) {\n\t\tthis.mOnCardSelectedListener = onCardSelectedListener;\n\t}\n\n\tprivate void resetDefaults() {\n\t\tmOnCardSelectedListener = null;\n\t}\n\n\tprivate void handleArgs(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n\t\tresetDefaults();\n\n\t\tfinal TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CardStackLayout, defStyleAttr,\n\t\t\t\tdefStyleRes);\n\t\tmParallaxEnabled = a.getBoolean(R.styleable.CardStackLayout_parallax_enabled, PARALLAX_ENABLED_DEFAULT);\n\t\tmShowInitAnimation = a.getBoolean(R.styleable.CardStackLayout_showInitAnimation, SHOW_INIT_ANIMATION_DEFAULT);\n\t\tmParallaxScale = a.getInteger(R.styleable.CardStackLayout_parallax_scale,\n\t\t\t\tgetResources().getInteger(R.integer.parallax_scale_default));\n\t\tmCardGap = a.getDimension(R.styleable.CardStackLayout_card_gap, getResources().getDimension(R.dimen.card_gap));\n\t\tmCardGapBottom = a.getDimension(R.styleable.CardStackLayout_card_gap_bottom,\n\t\t\t\tgetResources().getDimension(R.dimen.card_gap_bottom));\n\n\t\ta.recycle();\n\t}\n\n\t/**\n\t * @return adapter of type {@link CardStackAdapter} that is set for this\n\t *         view.\n\t */\n\tpublic CardStackAdapter getAdapter() {\n\t\treturn mAdapter;\n\t}\n\n\t/**\n\t * Set the adapter for this {@link CardStackLayout}\n\t *\n\t * @param adapter\n\t *            Should extend {@link CardStackAdapter}\n\t */\n\tpublic void setAdapter(CardStackAdapter adapter) {\n\t\tthis.mAdapter = adapter;\n\t\tmAdapter.setAdapterParams(this);\n\t\tfor (int i = 0; i < mAdapter.getCount(); i++) {\n\t\t\tmAdapter.addView(i);\n\t\t}\n\n\t\tif (mShowInitAnimation) {\n\t\t\tpostDelayed(this::restoreCards, 500);\n\t\t}\n\t}\n\n\t/**\n\t * @return currently set parallax scale value.\n\t */\n\tpublic int getParallaxScale() {\n\t\treturn mParallaxScale;\n\t}\n\n\t/**\n\t * Sets the value of parallax scale. Parallax scale is the factor which\n\t * decides how much distance a card will scroll when the user drags it down.\n\t */\n\tpublic void setParallaxScale(int mParallaxScale) {\n\t\tthis.mParallaxScale = mParallaxScale;\n\t}\n\n\tpublic boolean isParallaxEnabled() {\n\t\treturn mParallaxEnabled;\n\t}\n\n\tpublic void setParallaxEnabled(boolean mParallaxEnabled) {\n\t\tthis.mParallaxEnabled = mParallaxEnabled;\n\t}\n\n\tpublic boolean isShowInitAnimation() {\n\t\treturn mShowInitAnimation;\n\t}\n\n\tpublic void setShowInitAnimation(boolean mShowInitAnimation) {\n\t\tthis.mShowInitAnimation = mShowInitAnimation;\n\t}\n\n\t/**\n\t * @return the gap (in pixels) between two consecutive cards\n\t */\n\tpublic float getCardGap() {\n\t\treturn mCardGap;\n\t}\n\n\t/**\n\t * Set the gap (in pixels) between two consecutive cards\n\t */\n\tpublic void setCardGap(float mCardGap) {\n\t\tthis.mCardGap = mCardGap;\n\t}\n\n\t/**\n\t * @return gap between the two consecutive cards when collapsed to the\n\t *         bottom of the screen\n\t */\n\tpublic float getCardGapBottom() {\n\t\treturn mCardGapBottom;\n\t}\n\n\tpublic void setCardGapBottom(float mCardGapBottom) {\n\t\tthis.mCardGapBottom = mCardGapBottom;\n\t}\n\n\t/**\n\t * @return true if a card is selected, false otherwise\n\t */\n\tpublic boolean isCardSelected() {\n\t\treturn mAdapter.isCardSelected();\n\t}\n\n\t/**\n\t * Removes the adapter that was previously set using\n\t * {@link #setAdapter(CardStackAdapter)}\n\t */\n\tpublic void removeAdapter() {\n\t\tif (getChildCount() > 0)\n\t\t\tremoveAllViews();\n\t\tmAdapter = null;\n\t\tmOnCardSelectedListener = null;\n\t}\n\n\t/**\n\t * Animates the cards to their initial position in the layout.\n\t */\n\tpublic void restoreCards() {\n\t\tmAdapter.resetCards();\n\t}\n\n\t/**\n\t * Intimates the implementing class about the selection of a card\n\t */\n\tpublic interface OnCardSelected {\n\t\tvoid onCardSelected(View v, int position);\n\t}\n\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/DragSelectRecyclerView.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport io.virtualapp.R;\n\n/**\n * @author Aidan Follestad (afollestad)\n */\npublic class DragSelectRecyclerView extends RecyclerView {\n\n    private static final boolean LOGGING = false;\n    private static final int AUTO_SCROLL_DELAY = 25;\n    private int mLastDraggedIndex = -1;\n    private DragSelectRecyclerViewAdapter<?> mAdapter;\n    private int mInitialSelection;\n    private boolean mDragSelectActive;\n    private int mMinReached;\n    private int mMaxReached;\n    private int mHotspotHeight;\n    private int mHotspotOffsetTop;\n    private int mHotspotOffsetBottom;\n    private int mHotspotTopBoundStart;\n    private int mHotspotTopBoundEnd;\n    private int mHotspotBottomBoundStart;\n    private int mHotspotBottomBoundEnd;\n    private int mAutoScrollVelocity;\n    private FingerListener mFingerListener;\n    private boolean mInTopHotspot;\n    private boolean mInBottomHotspot;\n    private Handler mAutoScrollHandler;\n    private Runnable mAutoScrollRunnable = new Runnable() {\n        @Override\n        public void run() {\n            if (mAutoScrollHandler == null)\n                return;\n            if (mInTopHotspot) {\n                scrollBy(0, -mAutoScrollVelocity);\n                mAutoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY);\n            } else if (mInBottomHotspot) {\n                scrollBy(0, mAutoScrollVelocity);\n                mAutoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY);\n            }\n        }\n    };\n    private RectF mTopBoundRect;\n    private RectF mBottomBoundRect;\n    private Paint mDebugPaint;\n    private boolean mDebugEnabled = false;\n\n    public DragSelectRecyclerView(Context context) {\n        super(context);\n        init(context, null);\n    }\n\n    public DragSelectRecyclerView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    public DragSelectRecyclerView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init(context, attrs);\n    }\n\n    private static void LOG(String message, Object... args) {\n        //noinspection PointlessBooleanExpression\n        if (!LOGGING) return;\n        if (args != null) {\n            Log.d(\"DragSelectRecyclerView\", String.format(message, args));\n        } else {\n            Log.d(\"DragSelectRecyclerView\", message);\n        }\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        mAutoScrollHandler = new Handler();\n        final int defaultHotspotHeight = context.getResources().getDimensionPixelSize(R.dimen.dsrv_defaultHotspotHeight);\n\n        if (attrs != null) {\n            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DragSelectRecyclerView, 0, 0);\n            try {\n                boolean autoScrollEnabled = a.getBoolean(R.styleable.DragSelectRecyclerView_dsrv_autoScrollEnabled, true);\n                if (!autoScrollEnabled) {\n                    mHotspotHeight = -1;\n                    mHotspotOffsetTop = -1;\n                    mHotspotOffsetBottom = -1;\n                    LOG(\"Auto-scroll disabled\");\n                } else {\n                    mHotspotHeight = a.getDimensionPixelSize(\n                            R.styleable.DragSelectRecyclerView_dsrv_autoScrollHotspotHeight, defaultHotspotHeight);\n                    mHotspotOffsetTop = a.getDimensionPixelSize(\n                            R.styleable.DragSelectRecyclerView_dsrv_autoScrollHotspot_offsetTop, 0);\n                    mHotspotOffsetBottom = a.getDimensionPixelSize(\n                            R.styleable.DragSelectRecyclerView_dsrv_autoScrollHotspot_offsetBottom, 0);\n                    LOG(\"Hotspot height = %d\", mHotspotHeight);\n                }\n            } finally {\n                a.recycle();\n            }\n        } else {\n            mHotspotHeight = defaultHotspotHeight;\n            LOG(\"Hotspot height = %d\", mHotspotHeight);\n        }\n    }\n\n    public void setFingerListener(@Nullable FingerListener listener) {\n        this.mFingerListener = listener;\n    }\n\n    @Override\n    protected void onMeasure(int widthSpec, int heightSpec) {\n        super.onMeasure(widthSpec, heightSpec);\n        if (mHotspotHeight > -1) {\n            mHotspotTopBoundStart = mHotspotOffsetTop;\n            mHotspotTopBoundEnd = mHotspotOffsetTop + mHotspotHeight;\n            mHotspotBottomBoundStart = (getMeasuredHeight() - mHotspotHeight) - mHotspotOffsetBottom;\n            mHotspotBottomBoundEnd = getMeasuredHeight() - mHotspotOffsetBottom;\n            LOG(\"RecyclerView height = %d\", getMeasuredHeight());\n            LOG(\"Hotspot top bound = %d to %d\", mHotspotTopBoundStart, mHotspotTopBoundStart);\n            LOG(\"Hotspot bottom bound = %d to %d\", mHotspotBottomBoundStart, mHotspotBottomBoundEnd);\n        }\n    }\n\n    public boolean setDragSelectActive(boolean active, int initialSelection) {\n        if (active && mDragSelectActive) {\n            LOG(\"Drag selection is already active.\");\n            return false;\n        }\n        mLastDraggedIndex = -1;\n        mMinReached = -1;\n        mMaxReached = -1;\n        if (!mAdapter.isIndexSelectable(initialSelection)) {\n            mDragSelectActive = false;\n            mInitialSelection = -1;\n            mLastDraggedIndex = -1;\n            LOG(\"Index %d is not selectable.\", initialSelection);\n            return false;\n        }\n        mAdapter.setSelected(initialSelection, true);\n        mDragSelectActive = active;\n        mInitialSelection = initialSelection;\n        mLastDraggedIndex = initialSelection;\n        if (mFingerListener != null)\n            mFingerListener.onDragSelectFingerAction(true);\n        LOG(\"Drag selection initialized, starting at index %d.\", initialSelection);\n        return true;\n    }\n\n    /**\n     * Use {@link #setAdapter(DragSelectRecyclerViewAdapter)} instead.\n     */\n    @Override\n    @Deprecated\n    public void setAdapter(Adapter adapter) {\n        if (!(adapter instanceof DragSelectRecyclerViewAdapter<?>))\n            throw new IllegalArgumentException(\"Adapter must be a DragSelectRecyclerViewAdapter.\");\n        setAdapter((DragSelectRecyclerViewAdapter<?>) adapter);\n    }\n\n    public void setAdapter(DragSelectRecyclerViewAdapter<?> adapter) {\n        super.setAdapter(adapter);\n        mAdapter = adapter;\n    }\n\n    private int getItemPosition(MotionEvent e) {\n        final View v = findChildViewUnder(e.getX(), e.getY());\n        if (v == null) return NO_POSITION;\n        if (v.getTag() == null || !(v.getTag() instanceof ViewHolder))\n            throw new IllegalStateException(\"Make sure your adapter makes a call to super.onBindViewHolder(), and doesn't override itemView tags.\");\n        final ViewHolder holder = (ViewHolder) v.getTag();\n        return holder.getAdapterPosition();\n    }\n\n    public final void enableDebug() {\n        mDebugEnabled = true;\n        invalidate();\n    }\n\n    @Override\n    public void onDraw(Canvas c) {\n        super.onDraw(c);\n\n        if (mDebugEnabled) {\n            if (mDebugPaint == null) {\n                mDebugPaint = new Paint();\n                mDebugPaint.setColor(Color.BLACK);\n                mDebugPaint.setAntiAlias(true);\n                mDebugPaint.setStyle(Paint.Style.FILL);\n                mTopBoundRect = new RectF(0, mHotspotTopBoundStart, getMeasuredWidth(), mHotspotTopBoundEnd);\n                mBottomBoundRect = new RectF(0, mHotspotBottomBoundStart, getMeasuredWidth(), mHotspotBottomBoundEnd);\n            }\n            c.drawRect(mTopBoundRect, mDebugPaint);\n            c.drawRect(mBottomBoundRect, mDebugPaint);\n        }\n    }\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent e) {\n        if (mAdapter.getItemCount() == 0)\n            return super.dispatchTouchEvent(e);\n\n        if (mDragSelectActive) {\n            if (e.getAction() == MotionEvent.ACTION_UP) {\n                mDragSelectActive = false;\n                mInTopHotspot = false;\n                mInBottomHotspot = false;\n                mAutoScrollHandler.removeCallbacks(mAutoScrollRunnable);\n                if (mFingerListener != null)\n                    mFingerListener.onDragSelectFingerAction(false);\n                return true;\n            } else if (e.getAction() == MotionEvent.ACTION_MOVE) {\n                // Check for auto-scroll hotspot\n                if (mHotspotHeight > -1) {\n                    if (e.getY() >= mHotspotTopBoundStart && e.getY() <= mHotspotTopBoundEnd) {\n                        mInBottomHotspot = false;\n                        if (!mInTopHotspot) {\n                            mInTopHotspot = true;\n                            LOG(\"Now in TOP hotspot\");\n                            mAutoScrollHandler.removeCallbacks(mAutoScrollRunnable);\n                            mAutoScrollHandler.postDelayed(mAutoScrollRunnable, AUTO_SCROLL_DELAY);\n                        }\n\n                        final float simulatedFactor = mHotspotTopBoundEnd - mHotspotTopBoundStart;\n                        final float simulatedY = e.getY() - mHotspotTopBoundStart;\n                        mAutoScrollVelocity = (int) (simulatedFactor - simulatedY) / 2;\n\n                        LOG(\"Auto scroll velocity = %d\", mAutoScrollVelocity);\n                    } else if (e.getY() >= mHotspotBottomBoundStart && e.getY() <= mHotspotBottomBoundEnd) {\n                        mInTopHotspot = false;\n                        if (!mInBottomHotspot) {\n                            mInBottomHotspot = true;\n                            LOG(\"Now in BOTTOM hotspot\");\n                            mAutoScrollHandler.removeCallbacks(mAutoScrollRunnable);\n                            mAutoScrollHandler.postDelayed(mAutoScrollRunnable, AUTO_SCROLL_DELAY);\n                        }\n\n                        final float simulatedY = e.getY() + mHotspotBottomBoundEnd;\n                        final float simulatedFactor = mHotspotBottomBoundStart + mHotspotBottomBoundEnd;\n                        mAutoScrollVelocity = (int) (simulatedY - simulatedFactor) / 2;\n\n                        LOG(\"Auto scroll velocity = %d\", mAutoScrollVelocity);\n                    } else if (mInTopHotspot || mInBottomHotspot) {\n                        LOG(\"Left the hotspot\");\n                        mAutoScrollHandler.removeCallbacks(mAutoScrollRunnable);\n                        mInTopHotspot = false;\n                        mInBottomHotspot = false;\n                    }\n                }\n\n                // Drag selection logic\n                // NOTE: DISABLE IT\n//                if (itemPosition != NO_POSITION && mLastDraggedIndex != itemPosition) {\n//                    mLastDraggedIndex = itemPosition;\n//                    if (mMinReached == -1) mMinReached = mLastDraggedIndex;\n//                    if (mMaxReached == -1) mMaxReached = mLastDraggedIndex;\n//                    if (mLastDraggedIndex > mMaxReached)\n//                        mMaxReached = mLastDraggedIndex;\n//                    if (mLastDraggedIndex < mMinReached)\n//                        mMinReached = mLastDraggedIndex;\n//                    if (mAdapter != null)\n//                        mAdapter.selectRange(mInitialSelection, mLastDraggedIndex, mMinReached, mMaxReached);\n//                    if (mInitialSelection == mLastDraggedIndex) {\n//                        mMinReached = mLastDraggedIndex;\n//                        mMaxReached = mLastDraggedIndex;\n//                    }\n//                }\n                return true;\n            }\n        }\n        return super.dispatchTouchEvent(e);\n    }\n\n    public interface FingerListener {\n        void onDragSelectFingerAction(boolean fingerDown);\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/DragSelectRecyclerViewAdapter.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.os.Bundle;\nimport android.support.annotation.CallSuper;\nimport android.support.v7.widget.RecyclerView;\n\nimport java.util.ArrayList;\n\n/**\n * @author Aidan Follestad (afollestad)\n */\npublic abstract class DragSelectRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {\n\n    private ArrayList<Integer> mSelectedIndices;\n    private SelectionListener mSelectionListener;\n    private int mLastCount = -1;\n    private int mMaxSelectionCount = -1;\n    protected DragSelectRecyclerViewAdapter() {\n        mSelectedIndices = new ArrayList<>();\n    }\n\n    private void fireSelectionListener() {\n        if (mLastCount == mSelectedIndices.size())\n            return;\n        mLastCount = mSelectedIndices.size();\n        if (mSelectionListener != null)\n            mSelectionListener.onDragSelectionChanged(mLastCount);\n    }\n\n    public void setMaxSelectionCount(int maxSelectionCount) {\n        this.mMaxSelectionCount = maxSelectionCount;\n    }\n\n    public void setSelectionListener(SelectionListener selectionListener) {\n        this.mSelectionListener = selectionListener;\n    }\n\n    public void saveInstanceState(Bundle out) {\n        saveInstanceState(\"selected_indices\", out);\n    }\n\n    public void saveInstanceState(String key, Bundle out) {\n        out.putSerializable(key, mSelectedIndices);\n    }\n\n    public void restoreInstanceState(Bundle in) {\n        restoreInstanceState(\"selected_indices\", in);\n    }\n\n    public void restoreInstanceState(String key, Bundle in) {\n        if (in != null && in.containsKey(key)) {\n            //noinspection unchecked\n            mSelectedIndices = (ArrayList<Integer>) in.getSerializable(key);\n            if (mSelectedIndices == null) mSelectedIndices = new ArrayList<>();\n            else fireSelectionListener();\n        }\n    }\n\n    public final void setSelected(int index, boolean selected) {\n        if (!isIndexSelectable(index))\n            selected = false;\n        if (selected) {\n            if (!mSelectedIndices.contains(index) &&\n                    (mMaxSelectionCount == -1 ||\n                            mSelectedIndices.size() < mMaxSelectionCount)) {\n                mSelectedIndices.add(index);\n                notifyItemChanged(index);\n            }\n        } else if (mSelectedIndices.contains(index)) {\n            mSelectedIndices.remove((Integer) index);\n            notifyItemChanged(index);\n        }\n        fireSelectionListener();\n    }\n\n    public final boolean toggleSelected(int index) {\n        boolean selectedNow = false;\n        if (isIndexSelectable(index)) {\n            if (mSelectedIndices.contains(index)) {\n                mSelectedIndices.remove((Integer) index);\n            } else if (mMaxSelectionCount == -1 ||\n                    mSelectedIndices.size() < mMaxSelectionCount) {\n                mSelectedIndices.add(index);\n                selectedNow = true;\n            }\n            notifyItemChanged(index);\n        }\n        fireSelectionListener();\n        return selectedNow;\n    }\n\n    protected boolean isIndexSelectable(int index) {\n        return true;\n    }\n\n    @CallSuper\n    @Override\n    public void onBindViewHolder(VH holder, int position) {\n        holder.itemView.setTag(holder);\n    }\n\n    public final void selectRange(int from, int to, int min, int max) {\n        if (from == to) {\n            // Finger is back on the initial item, unselect everything else\n            for (int i = min; i <= max; i++) {\n                if (i == from) continue;\n                setSelected(i, false);\n            }\n            fireSelectionListener();\n            return;\n        }\n\n        if (to < from) {\n            // When selecting from one to previous items\n            for (int i = to; i <= from; i++)\n                setSelected(i, true);\n            if (min > -1 && min < to) {\n                // Unselect items that were selected during this drag but no longer are\n                for (int i = min; i < to; i++) {\n                    if (i == from) continue;\n                    setSelected(i, false);\n                }\n            }\n            if (max > -1) {\n                for (int i = from + 1; i <= max; i++)\n                    setSelected(i, false);\n            }\n        } else {\n            // When selecting from one to next items\n            for (int i = from; i <= to; i++)\n                setSelected(i, true);\n            if (max > -1 && max > to) {\n                // Unselect items that were selected during this drag but no longer are\n                for (int i = to + 1; i <= max; i++) {\n                    if (i == from) continue;\n                    setSelected(i, false);\n                }\n            }\n            if (min > -1) {\n                for (int i = min; i < from; i++)\n                    setSelected(i, false);\n            }\n        }\n        fireSelectionListener();\n    }\n\n    public final void selectAll() {\n        int max = getItemCount();\n        mSelectedIndices.clear();\n        for (int i = 0; i < max; i++) {\n            if (isIndexSelectable(i)) {\n                mSelectedIndices.add(i);\n            }\n        }\n        notifyDataSetChanged();\n        fireSelectionListener();\n    }\n\n    public final void clearSelected() {\n        mSelectedIndices.clear();\n        notifyDataSetChanged();\n        fireSelectionListener();\n    }\n\n    public final int getSelectedCount() {\n        return mSelectedIndices.size();\n    }\n\n    public final Integer[] getSelectedIndices() {\n        return mSelectedIndices.toArray(new Integer[mSelectedIndices.size()]);\n    }\n\n    public final boolean isIndexSelected(int index) {\n        return mSelectedIndices.contains(index);\n    }\n\n    public interface SelectionListener {\n        void onDragSelectionChanged(int count);\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/EatBeansView.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.animation.Animator;\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.util.AttributeSet;\n\n\npublic class EatBeansView extends BaseView {\n\n    int eatSpeed = 8;\n    private Paint mPaint, mPaintEye, mPaintBeans;\n    private float mWidth = 0f;\n    private float mHigh = 0f;\n    private float mPadding = 5f;\n    private float eatErWidth = 50f;\n    private float eatErPositionX = 0f;\n    private float beansWidth = 10f;\n\n\n    private float mAngle = 34;\n    private float eatErStartAngle = mAngle;\n    private float eatErEndAngle = 360 - 2 * eatErStartAngle;\n    private RectF mRect = new RectF();\n\n    public EatBeansView(Context context) {\n        super(context);\n    }\n\n    public EatBeansView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public EatBeansView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        mWidth = getMeasuredWidth();\n        mHigh = getMeasuredHeight();\n    }\n\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        float eatRightX = mPadding + eatErWidth + eatErPositionX;\n        mRect.set(mPadding + eatErPositionX, mHigh / 2 - eatErWidth / 2, eatRightX, mHigh / 2 + eatErWidth / 2);\n        canvas.drawArc(mRect, eatErStartAngle, eatErEndAngle\n                , true, mPaint);\n        canvas.drawCircle(mPadding + eatErPositionX + eatErWidth / 2,\n                mHigh / 2 - eatErWidth / 4,\n                beansWidth / 2, mPaintEye);\n\n        int beansCount = (int) ((mWidth - mPadding * 2 - eatErWidth) / beansWidth / 2);\n        for (int i = 0; i < beansCount; i++) {\n\n            float x = beansCount * i + beansWidth / 2 + mPadding + eatErWidth;\n            if (x > eatRightX) {\n                canvas.drawCircle(x,\n                        mHigh / 2, beansWidth / 2, mPaintBeans);\n            }\n        }\n\n\n    }\n\n    private void initPaint() {\n        mPaint = new Paint();\n        mPaint.setAntiAlias(true);\n        mPaint.setStyle(Paint.Style.FILL);\n        mPaint.setColor(0xDDDDDDDD);\n\n        mPaintBeans = new Paint();\n        mPaintBeans.setAntiAlias(true);\n        mPaintBeans.setStyle(Paint.Style.FILL);\n        mPaintBeans.setColor(0xFFBBBBBB);\n\n        mPaintEye = new Paint();\n        mPaintEye.setAntiAlias(true);\n        mPaintEye.setStyle(Paint.Style.FILL);\n        mPaintEye.setColor(0xFF888888);\n    }\n\n\n    public void setViewColor(int color) {\n        mPaint.setColor(color);\n        postInvalidate();\n    }\n\n    public void setEyeColor(int color) {\n        mPaintEye.setColor(color);\n        postInvalidate();\n    }\n\n\n    @Override\n    protected void InitPaint() {\n        initPaint();\n    }\n\n    @Override\n    protected void OnAnimationUpdate(ValueAnimator valueAnimator) {\n        float mAnimatedValue = (float) valueAnimator.getAnimatedValue();\n        eatErPositionX = (mWidth - 2 * mPadding - eatErWidth) * mAnimatedValue;\n        eatErStartAngle = mAngle * (1 - (mAnimatedValue * eatSpeed - (int) (mAnimatedValue * eatSpeed)));\n        eatErEndAngle = 360 - eatErStartAngle * 2;\n        invalidate();\n    }\n\n    @Override\n    protected void OnAnimationRepeat(Animator animation) {\n\n    }\n\n    @Override\n    protected int OnStopAnim() {\n        eatErPositionX = 0;\n        postInvalidate();\n        return 1;\n    }\n\n    @Override\n    protected int SetAnimRepeatMode() {\n        return ValueAnimator.RESTART;\n    }\n\n    @Override\n    protected void AnimIsRunning() {\n\n    }\n\n    @Override\n    protected int SetAnimRepeatCount() {\n        return ValueAnimator.INFINITE;\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/Indicator.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.animation.ValueAnimator;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\n\npublic abstract class Indicator extends Drawable implements Animatable {\n\n    private static final Rect ZERO_BOUNDS_RECT = new Rect();\n    protected Rect drawBounds = ZERO_BOUNDS_RECT;\n    private HashMap<ValueAnimator, ValueAnimator.AnimatorUpdateListener> mUpdateListeners = new HashMap<>();\n    private ArrayList<ValueAnimator> mAnimators;\n    private int alpha = 255;\n    private boolean mHasAnimators;\n\n    private Paint mPaint = new Paint();\n\n    public Indicator() {\n        mPaint.setColor(Color.WHITE);\n        mPaint.setStyle(Paint.Style.FILL);\n        mPaint.setAntiAlias(true);\n    }\n\n    public int getColor() {\n        return mPaint.getColor();\n    }\n\n    public void setColor(int color) {\n        mPaint.setColor(color);\n    }\n\n    @Override\n    public int getAlpha() {\n        return alpha;\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        this.alpha = alpha;\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.OPAQUE;\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter colorFilter) {\n\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n        draw(canvas, mPaint);\n    }\n\n    public abstract void draw(Canvas canvas, Paint paint);\n\n    public abstract ArrayList<ValueAnimator> onCreateAnimators();\n\n    @Override\n    public void start() {\n        ensureAnimators();\n\n        if (mAnimators == null) {\n            return;\n        }\n\n        // If the animators has not ended, do nothing.\n        if (isStarted()) {\n            return;\n        }\n        startAnimators();\n        invalidateSelf();\n    }\n\n    private void startAnimators() {\n        for (int i = 0; i < mAnimators.size(); i++) {\n            ValueAnimator animator = mAnimators.get(i);\n\n            //when the animator restart , add the updateListener again because they\n            // was removed by animator stop .\n            ValueAnimator.AnimatorUpdateListener updateListener = mUpdateListeners.get(animator);\n            if (updateListener != null) {\n                animator.addUpdateListener(updateListener);\n            }\n\n            animator.start();\n        }\n    }\n\n    private void stopAnimators() {\n        if (mAnimators != null) {\n            for (ValueAnimator animator : mAnimators) {\n                if (animator != null && animator.isStarted()) {\n                    animator.removeAllUpdateListeners();\n                    animator.end();\n                }\n            }\n        }\n    }\n\n    private void ensureAnimators() {\n        if (!mHasAnimators) {\n            mAnimators = onCreateAnimators();\n            mHasAnimators = true;\n        }\n    }\n\n    @Override\n    public void stop() {\n        stopAnimators();\n    }\n\n    private boolean isStarted() {\n        for (ValueAnimator animator : mAnimators) {\n            return animator.isStarted();\n        }\n        return false;\n    }\n\n    @Override\n    public boolean isRunning() {\n        for (ValueAnimator animator : mAnimators) {\n            return animator.isRunning();\n        }\n        return false;\n    }\n\n    /**\n     * Your should use this to add AnimatorUpdateListener when\n     * create animator , otherwise , animator doesn't work when\n     * the animation restart .\n     *\n     * @param updateListener\n     */\n    public void addUpdateListener(ValueAnimator animator, ValueAnimator.AnimatorUpdateListener updateListener) {\n        mUpdateListeners.put(animator, updateListener);\n    }\n\n    @Override\n    protected void onBoundsChange(Rect bounds) {\n        super.onBoundsChange(bounds);\n        setDrawBounds(bounds);\n    }\n\n    public void setDrawBounds(int left, int top, int right, int bottom) {\n        this.drawBounds = new Rect(left, top, right, bottom);\n    }\n\n    public void postInvalidate() {\n        invalidateSelf();\n    }\n\n    public Rect getDrawBounds() {\n        return drawBounds;\n    }\n\n    public void setDrawBounds(Rect drawBounds) {\n        setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom);\n    }\n\n    public int getWidth() {\n        return drawBounds.width();\n    }\n\n    public int getHeight() {\n        return drawBounds.height();\n    }\n\n    public int centerX() {\n        return drawBounds.centerX();\n    }\n\n    public int centerY() {\n        return drawBounds.centerY();\n    }\n\n    public float exactCenterX() {\n        return drawBounds.exactCenterX();\n    }\n\n    public float exactCenterY() {\n        return drawBounds.exactCenterY();\n    }\n\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/LabelView.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\n\nimport io.virtualapp.R;\n\npublic class LabelView extends View {\n    private static final int DEFAULT_DEGREES = 45;\n    private String mTextContent;\n    private int mTextColor;\n    private float mTextSize;\n    private boolean mTextBold;\n    private boolean mFillTriangle;\n    private boolean mTextAllCaps;\n    private int mBackgroundColor;\n    private float mMinSize;\n    private float mPadding;\n    private int mGravity;\n    private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n    private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n    private Path mPath = new Path();\n\n    public LabelView(Context context) {\n        this(context, null);\n    }\n\n    public LabelView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        obtainAttributes(context, attrs);\n        mTextPaint.setTextAlign(Paint.Align.CENTER);\n    }\n\n    private void obtainAttributes(Context context, AttributeSet attrs) {\n        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LabelView);\n        mTextContent = ta.getString(R.styleable.LabelView_lv_text);\n        mTextColor = ta.getColor(R.styleable.LabelView_lv_text_color, Color.parseColor(\"#ffffff\"));\n        mTextSize = ta.getDimension(R.styleable.LabelView_lv_text_size, sp2px(11));\n        mTextBold = ta.getBoolean(R.styleable.LabelView_lv_text_bold, true);\n        mTextAllCaps = ta.getBoolean(R.styleable.LabelView_lv_text_all_caps, true);\n        mFillTriangle = ta.getBoolean(R.styleable.LabelView_lv_fill_triangle, false);\n        mBackgroundColor = ta.getColor(R.styleable.LabelView_lv_background_color, Color.parseColor(\"#FF4081\"));\n        mMinSize = ta.getDimension(R.styleable.LabelView_lv_min_size, mFillTriangle ? dp2px(35) : dp2px(50));\n        mPadding = ta.getDimension(R.styleable.LabelView_lv_padding, dp2px(3.5f));\n        mGravity = ta.getInt(R.styleable.LabelView_lv_gravity, Gravity.TOP | Gravity.LEFT);\n        ta.recycle();\n    }\n\n    public String getText() {\n        return mTextContent;\n    }\n\n    public void setText(String text) {\n        mTextContent = text;\n        invalidate();\n    }\n\n    public int getTextColor() {\n        return mTextColor;\n    }\n\n    public void setTextColor(int textColor) {\n        mTextColor = textColor;\n        invalidate();\n    }\n\n    public float getTextSize() {\n        return mTextSize;\n    }\n\n    public void setTextSize(float textSize) {\n        mTextSize = sp2px(textSize);\n        invalidate();\n    }\n\n    public boolean isTextBold() {\n        return mTextBold;\n    }\n\n    public void setTextBold(boolean textBold) {\n        mTextBold = textBold;\n        invalidate();\n    }\n\n    public boolean isFillTriangle() {\n        return mFillTriangle;\n    }\n\n    public void setFillTriangle(boolean fillTriangle) {\n        mFillTriangle = fillTriangle;\n        invalidate();\n    }\n\n    public boolean isTextAllCaps() {\n        return mTextAllCaps;\n    }\n\n    public void setTextAllCaps(boolean textAllCaps) {\n        mTextAllCaps = textAllCaps;\n        invalidate();\n    }\n\n    public int getBgColor() {\n        return mBackgroundColor;\n    }\n\n    public void setBgColor(int backgroundColor) {\n        mBackgroundColor = backgroundColor;\n        invalidate();\n    }\n\n    public float getMinSize() {\n        return mMinSize;\n    }\n\n    public void setMinSize(float minSize) {\n        mMinSize = dp2px(minSize);\n        invalidate();\n    }\n\n    public float getPadding() {\n        return mPadding;\n    }\n\n    public void setPadding(float padding) {\n        mPadding = dp2px(padding);\n        invalidate();\n    }\n\n    public int getGravity() {\n        return mGravity;\n    }\n\n    /**\n     * Gravity.TOP | Gravity.LEFT\n     * Gravity.TOP | Gravity.RIGHT\n     * Gravity.BOTTOM | Gravity.LEFT\n     * Gravity.BOTTOM | Gravity.RIGHT\n     */\n    public void setGravity(int gravity) {\n        mGravity = gravity;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        int size = getHeight();\n\n        mTextPaint.setColor(mTextColor);\n        mTextPaint.setTextSize(mTextSize);\n        mTextPaint.setFakeBoldText(mTextBold);\n        mBackgroundPaint.setColor(mBackgroundColor);\n\n        float textHeight = mTextPaint.descent() - mTextPaint.ascent();\n        if (mFillTriangle) {\n            if (mGravity == (Gravity.TOP | Gravity.LEFT)) {\n                mPath.reset();\n                mPath.moveTo(0, 0);\n                mPath.lineTo(0, size);\n                mPath.lineTo(size, 0);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, true);\n            } else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) {\n                mPath.reset();\n                mPath.moveTo(size, 0);\n                mPath.lineTo(0, 0);\n                mPath.lineTo(size, size);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawTextWhenFill(size, DEFAULT_DEGREES, canvas, true);\n            } else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) {\n                mPath.reset();\n                mPath.moveTo(0, size);\n                mPath.lineTo(0, 0);\n                mPath.lineTo(size, size);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawTextWhenFill(size, DEFAULT_DEGREES, canvas, false);\n            } else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) {\n                mPath.reset();\n                mPath.moveTo(size, size);\n                mPath.lineTo(0, size);\n                mPath.lineTo(size, 0);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, false);\n            }\n        } else {\n            double delta = (textHeight + mPadding * 2) * Math.sqrt(2);\n            if (mGravity == (Gravity.TOP | Gravity.LEFT)) {\n                mPath.reset();\n                mPath.moveTo(0, (float) (size - delta));\n                mPath.lineTo(0, size);\n                mPath.lineTo(size, 0);\n                mPath.lineTo((float) (size - delta), 0);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawText(size, -DEFAULT_DEGREES, canvas, textHeight, true);\n            } else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) {\n                mPath.reset();\n                mPath.moveTo(0, 0);\n                mPath.lineTo((float) delta, 0);\n                mPath.lineTo(size, (float) (size - delta));\n                mPath.lineTo(size, size);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawText(size, DEFAULT_DEGREES, canvas, textHeight, true);\n            } else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) {\n                mPath.reset();\n                mPath.moveTo(0, 0);\n                mPath.lineTo(0, (float) delta);\n                mPath.lineTo((float) (size - delta), size);\n                mPath.lineTo(size, size);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawText(size, DEFAULT_DEGREES, canvas, textHeight, false);\n            } else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) {\n                mPath.reset();\n                mPath.moveTo(0, size);\n                mPath.lineTo((float) delta, size);\n                mPath.lineTo(size, (float) delta);\n                mPath.lineTo(size, 0);\n                mPath.close();\n                canvas.drawPath(mPath, mBackgroundPaint);\n\n                drawText(size, -DEFAULT_DEGREES, canvas, textHeight, false);\n            }\n        }\n    }\n\n    private void drawText(int size, float degrees, Canvas canvas, float textHeight, boolean isTop) {\n        canvas.save();\n        canvas.rotate(degrees, size / 2f, size / 2f);\n        float delta = isTop ? -(textHeight + mPadding * 2) / 2 : (textHeight + mPadding * 2) / 2;\n        float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta;\n        canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent,\n                getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint);\n        canvas.restore();\n    }\n\n    private void drawTextWhenFill(int size, float degrees, Canvas canvas, boolean isTop) {\n        canvas.save();\n        canvas.rotate(degrees, size / 2f, size / 2f);\n        float delta = isTop ? -size / 4 : size / 4;\n        float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta;\n        canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent,\n                getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint);\n        canvas.restore();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int measuredWidth = measureWidth(widthMeasureSpec);\n        setMeasuredDimension(measuredWidth, measuredWidth);\n    }\n\n    /**\n     * 确定View宽度大小\n     */\n    private int measureWidth(int widthMeasureSpec) {\n        int result;\n        int specMode = MeasureSpec.getMode(widthMeasureSpec);\n        int specSize = MeasureSpec.getSize(widthMeasureSpec);\n        if (specMode == MeasureSpec.EXACTLY) {//大小确定直接使用\n            result = specSize;\n        } else {\n            int padding = getPaddingLeft() + getPaddingRight();\n            mTextPaint.setColor(mTextColor);\n            mTextPaint.setTextSize(mTextSize);\n            float textWidth = mTextPaint.measureText(mTextContent + \"\");\n            result = (int) ((padding + (int) textWidth) * Math.sqrt(2));\n            //如果父视图的测量要求为AT_MOST,即限定了一个最大值,则再从系统建议值和自己计算值中去一个较小值\n            if (specMode == MeasureSpec.AT_MOST) {\n                result = Math.min(result, specSize);\n            }\n\n            result = Math.max((int) mMinSize, result);\n        }\n\n        return result;\n    }\n\n    protected int dp2px(float dp) {\n        final float scale = getResources().getDisplayMetrics().density;\n        return (int) (dp * scale + 0.5f);\n    }\n\n    protected int sp2px(float sp) {\n        final float scale = getResources().getDisplayMetrics().scaledDensity;\n        return (int) (sp * scale + 0.5f);\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/MarqueeTextView.java",
    "content": "package io.virtualapp.widgets;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.support.v7.widget.AppCompatTextView;\nimport android.util.AttributeSet;\n\npublic class MarqueeTextView extends AppCompatTextView {\n\n    private boolean isStop = false;\n\n    public MarqueeTextView(Context context) {\n        super(context);\n    }\n\n    public MarqueeTextView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public boolean isFocused() {\n        if (this.isStop) {\n            return super.isFocused();\n        }\n        return true;\n    }\n\n    public void stopScroll() {\n        this.isStop = true;\n    }\n\n    public void start() {\n        this.isStop = false;\n    }\n\n    protected void onDetachedFromWindow() {\n        stopScroll();\n        super.onDetachedFromWindow();\n    }\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/fittext/BaseTextView.java",
    "content": "package io.virtualapp.widgets.fittext;\n\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.os.Build;\nimport android.text.Layout;\nimport android.text.TextPaint;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\n\nclass BaseTextView extends TextView {\n    protected boolean mSingleLine = false;\n    protected boolean mIncludeFontPadding = true;\n    protected float mLineSpacingMult = 1;\n    protected float mLineSpacingAdd = 0;\n    protected int mMaxLines = Integer.MAX_VALUE;\n    protected boolean mLineEndNoSpace = true;\n    protected boolean mJustify = false;\n\n    /***\n     * 不拆分单词\n     */\n    protected boolean mKeepWord = true;\n    @SuppressWarnings(\"deprecation\")\n    private static final int[] ANDROID_ATTRS = new int[]{\n            android.R.attr.includeFontPadding,\n            android.R.attr.lineSpacingMultiplier,\n            android.R.attr.lineSpacingExtra,\n            android.R.attr.maxLines,\n            android.R.attr.singleLine,\n            };\n\n    public BaseTextView(Context context) {\n        this(context, null);\n    }\n\n    public BaseTextView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        if (attrs != null) {\n            TypedArray a = context.obtainStyledAttributes(attrs, ANDROID_ATTRS);\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {\n                mIncludeFontPadding = a.getBoolean(a.getIndex(0),  mIncludeFontPadding);\n                mLineSpacingMult = a.getFloat(a.getIndex(1),  mLineSpacingMult);\n                mLineSpacingAdd = a.getDimensionPixelSize(a.getIndex(2),  (int) mLineSpacingAdd);\n                mMaxLines = a.getInteger(a.getIndex(3), mMaxLines);\n            }\n            mSingleLine = a.getBoolean(android.R.attr.singleLine, mSingleLine);\n            a.recycle();\n        }\n    }\n\n    public BaseTextView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs);\n    }\n\n    public boolean isKeepWord() {\n        return mKeepWord;\n    }\n\n    public void setKeepWord(boolean keepWord) {\n        mKeepWord = keepWord;\n    }\n\n    public boolean isJustify() {\n        return mJustify;\n    }\n\n    public void setJustify(boolean justify) {\n        mJustify = justify;\n    }\n\n    public boolean isLineEndNoSpace() {\n        return mLineEndNoSpace;\n    }\n\n    public void setLineEndNoSpace(boolean lineEndNoSpace) {\n        mLineEndNoSpace = lineEndNoSpace;\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public boolean getIncludeFontPaddingCompat() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return getIncludeFontPadding();\n        } else {\n            return mIncludeFontPadding;\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public float getLineSpacingMultiplierCompat() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return getLineSpacingMultiplier();\n        } else {\n            return mLineSpacingMult;\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public float getLineSpacingExtraCompat() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return getLineSpacingExtra();\n        } else {\n            return mLineSpacingAdd;\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public int getMaxLinesCompat() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return getMaxLines();\n        } else {\n            return mMaxLines;\n        }\n    }\n\n    @Override\n    public void setLineSpacing(float add, float mult) {\n        super.setLineSpacing(add, mult);\n        mLineSpacingAdd = add;\n        mLineSpacingMult = mult;\n    }\n\n    @Override\n    public void setIncludeFontPadding(boolean includepad) {\n        super.setIncludeFontPadding(includepad);\n        mIncludeFontPadding = includepad;\n    }\n\n    @Override\n    public void setMaxLines(int maxlines) {\n        super.setMaxLines(maxlines);\n        mMaxLines = maxlines;\n    }\n\n    @Override\n    public void setSingleLine(boolean singleLine) {\n        super.setSingleLine(singleLine);\n        mSingleLine = singleLine;\n    }\n\n\n    public int getTextWidth() {\n        return FitTextHelper.getTextWidth(this);\n    }\n\n    public int getTextHeight() {\n        return getMeasuredHeight() - getCompoundPaddingTop()\n                - getCompoundPaddingBottom();\n    }\n\n    /**\n     * 设置粗体\n     *\n     * @param bold 粗体\n     */\n    public void setBoldText(boolean bold) {\n        getPaint().setFakeBoldText(bold);\n    }\n\n    /**\n     * 设置斜体\n     *\n     * @param italic 斜体\n     */\n    public void setItalicText(boolean italic) {\n        getPaint().setTextSkewX(italic ? -0.25f : 0f);\n    }\n\n    public boolean isItalicText() {\n        return getPaint().getTextSkewX() != 0f;\n    }\n\n    public boolean isSingleLine() {\n        return mSingleLine;\n    }\n\n    public float getTextLineHeight() {\n        return getLineHeight();\n    }\n\n    public TextView getTextView() {\n        return this;\n    }\n\n    protected void onDraw(Canvas canvas) {\n        if (!mJustify || mSingleLine) {\n            super.onDraw(canvas);\n            return;\n        }\n        TextPaint paint = getPaint();\n//        paint.drawableState = getDrawableState();\n        float mViewWidth = getTextWidth();\n        if (isItalicText()) {\n            float letterW = getPaint().measureText(\"a\");\n            mViewWidth -= letterW;\n        }\n        CharSequence text = getText();\n        Layout layout = getLayout();\n        if (layout == null) {\n            layout = FitTextHelper.getStaticLayout(this, getText(), getPaint());\n        }\n        int count = layout.getLineCount();\n        for (int i = 0; i < count; i++) {\n            int lineStart = layout.getLineStart(i);\n            int lineEnd = layout.getLineEnd(i);\n//            int top = layout.getLineTop(i);\n            float x = layout.getLineLeft(i);\n            int mLineY = layout.getTopPadding() + (i + 1) * getLineHeight();\n            CharSequence line = text.subSequence(lineStart, lineEnd);\n            if (line.length() == 0) {\n                continue;\n            }\n            if (mLineEndNoSpace) {\n                if (TextUtils.equals(line.subSequence(line.length() - 1, line.length()), \" \")) {\n                    line = line.subSequence(0, line.length() - 1);\n                }\n                if (TextUtils.equals(line.subSequence(0, 1), \" \")) {\n                    line = line.subSequence(1, line.length() - 1);\n                }\n            }\n            float lineWidth = getPaint().measureText(text, lineStart, lineEnd);\n            boolean needScale = i < (count - 1) && (needScale(text.subSequence(lineEnd - 1, lineEnd)));\n//            if (i < (count - 1) && needScale(line)) {\n\n            //float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());\n//                drawScaledText(canvas, mViewWidth, mLineY, lineStart, line, width - getCompoundPaddingLeft() - getCompoundPaddingRight());\n//            } else {\n//                canvas.drawText(line, 0, line.length(), 0, mLineY, paint);\n//            }\n//            float x = getCompoundPaddingLeft();\n            if (needScale && mViewWidth > lineWidth) {\n//                float sc = mViewWidth / lineWidth;\n                //标点数\n                int clen = countEmpty(line);\n                float d = (mViewWidth - lineWidth) / clen;\n                for (int j = 0; j < line.length(); j++) {\n                    float cw = getPaint().measureText(line, j, j + 1);\n                    canvas.drawText(line, j, j + 1, x, mLineY, getPaint());\n                    x += cw;\n                    // 后面是标点\n                    if (isEmpty(line, j + 1, j + 2)) {\n                        x += d / 2;\n                    }\n                    //当前是标点\n                    if (isEmpty(line, j, j + 1)) {\n                        x += d / 2;\n                    }\n                }\n            } else {\n                canvas.drawText(line, 0, line.length(), x, mLineY, paint);\n            }\n        }\n    }\n\n    /**\n     * 共有多少个标点/空白字符\n     *\n     * @param text 内容\n     * @return 数量\n     */\n    protected int countEmpty(CharSequence text) {\n        int len = text.length();\n        int count = 0;\n        for (int i = 0; i < len; i++) {\n            if (isEmpty(text, i, i + 1)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    /**\n     * 是否是标点/空白字符\n     *\n     * @param c     内容\n     * @param start 开始\n     * @param end   结束\n     */\n    protected boolean isEmpty(CharSequence c, int start, int end) {\n        if (end >= c.length()) {\n            return false;\n        }\n        CharSequence ch = c.subSequence(start, end);\n        return TextUtils.equals(ch, \"\\t\") || TextUtils.equals(ch, \" \") || FitTextHelper.sSpcaeList.contains(ch);\n    }\n\n//    private void drawScaledText(Canvas canvas, int mViewWidth, int mLineY, int lineStart, CharSequence line, float lineWidth) {\n//        float x = 0;\n//        if (isFirstLineOfParagraph(lineStart, line)) {\n//            String blanks = \"  \";\n//            canvas.drawText(blanks, x, mLineY, getPaint());\n//            float bw = StaticLayout.getDesiredWidth(blanks, getPaint());\n//            x += bw;\n//\n//            line = line.subSequence(3, line.length() - 3);\n//        }\n//\n//        float d = (mViewWidth - lineWidth) / line.length() - 1;\n//        for (int i = 0; i < line.length(); i++) {\n//            String c = String.valueOf(line.charAt(i));\n//            float cw = StaticLayout.getDesiredWidth(c, getPaint());\n//            canvas.drawText(c, x, mLineY, getPaint());\n//            x += cw + d;\n//        }\n//    }\n//\n//    private boolean isFirstLineOfParagraph(int lineStart, CharSequence line) {\n//        return line.length() > 3 && line.charAt(0) == ' ' && line.charAt(1) == ' ';\n//    }\n\n    /**\n     * 是否需要两端对齐\n     *\n     * @param end 结束字符\n     */\n    protected boolean needScale(CharSequence end) {\n        return TextUtils.equals(end, \" \");// || !TextUtils.equals(end, \"\\n\");\n    }\n\n}"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/fittext/FitTextHelper.java",
    "content": "package io.virtualapp.widgets.fittext;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.text.Layout;\nimport android.text.SpannableStringBuilder;\nimport android.text.StaticLayout;\nimport android.text.TextPaint;\nimport android.text.TextUtils;\nimport android.view.Gravity;\nimport android.view.inputmethod.EditorInfo;\nimport android.widget.TextView;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/***\n * 两端对齐\n * 标点句尾\n */\nclass FitTextHelper {\n    protected static final float LIMIT = 0.001f;// 误差\n    private static final boolean LastNoSpace = false;\n    protected BaseTextView textView;\n\n    //region space list\n    public final static List<CharSequence> sSpcaeList = new ArrayList<>();\n\n    static {\n        sSpcaeList.add(\",\");\n        sSpcaeList.add(\".\");\n        sSpcaeList.add(\";\");\n        sSpcaeList.add(\"'\");\n        sSpcaeList.add(\"\\\"\");\n        sSpcaeList.add(\":\");\n        sSpcaeList.add(\"?\");\n        sSpcaeList.add(\"~\");\n        sSpcaeList.add(\"!\");\n        sSpcaeList.add(\"‘\");\n        sSpcaeList.add(\"’\");\n        sSpcaeList.add(\"”\");\n        sSpcaeList.add(\"“\");\n        sSpcaeList.add(\"；\");\n        sSpcaeList.add(\"：\");\n        sSpcaeList.add(\"，\");\n        sSpcaeList.add(\"。\");\n        sSpcaeList.add(\"？\");\n        sSpcaeList.add(\"！\");\n        sSpcaeList.add(\"(\");\n        sSpcaeList.add(\")\");\n        sSpcaeList.add(\"[\");\n        sSpcaeList.add(\"]\");\n        sSpcaeList.add(\"@\");\n        sSpcaeList.add(\"/\");\n        sSpcaeList.add(\"#\");\n        sSpcaeList.add(\"$\");\n        sSpcaeList.add(\"%\");\n        sSpcaeList.add(\"^\");\n        sSpcaeList.add(\"&\");\n        sSpcaeList.add(\"*\");\n//        sSpcaeList.add(\"{\");\n//        sSpcaeList.add(\"}\");\n        sSpcaeList.add(\"<\");\n        sSpcaeList.add(\">\");\n//        sSpcaeList.add(\"/\");\n//        sSpcaeList.add(\"\\\\\");\n        sSpcaeList.add(\"+\");\n        sSpcaeList.add(\"-\");\n        sSpcaeList.add(\"·\");\n//        sSpcaeList.add(\"●\");\n//        sSpcaeList.add(\"【\");\n//        sSpcaeList.add(\"】\");\n//        sSpcaeList.add(\"《\");\n//        sSpcaeList.add(\"》\");\n//        sSpcaeList.add(\"『\");\n//        sSpcaeList.add(\"』\");\n//        sSpcaeList.add(\"／\");\n    }\n    //endregion\n\n    protected volatile boolean mFittingText = false;\n\n    public FitTextHelper(BaseTextView textView) {\n        this.textView = textView;\n    }\n\n    /***\n     * @param textView textview\n     * @return 是否是单行\n     */\n    public static boolean isSingleLine(TextView textView) {\n        if (textView == null) return false;\n        if (textView instanceof BaseTextView) {\n            return ((BaseTextView) textView).isSingleLine();\n        }\n        if (textView == null) {\n            return false;\n        }\n        int type = textView.getInputType();\n        return (type & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;\n    }\n\n//    public float getLineHieght() {\n//        Paint.FontMetrics fm = textView.getPaint().getFontMetrics();\n//        float baseline = fm.descent - fm.ascent;\n//        float multi = textView.getLineSpacingMultiplierCompat();\n//        float space = textView.getLineSpacingExtraCompat();\n//        //字距\n//        return (baseline + fm.leading)\n//                * multi + space;\n//    }\n\n    /**\n     * @return 文本框的当前最大行数\n     */\n    protected int getMaxLineCount() {\n        float vspace = textView.getTextLineHeight();\n        float height = textView.getTextHeight();\n        return (int) (height / vspace);\n    }\n\n    //\n//    protected boolean isSingle(TextView textView) {\n//        int inputType = textView.getInputType();\n//        return (inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;\n//    }\n\n    /**\n     * 文本框的宽度\n     *\n     * @param textView 文本框\n     * @return 宽度\n     */\n    public static int getTextWidth(TextView textView) {\n        return textView.getMeasuredWidth() - textView.getCompoundPaddingLeft()\n                - textView.getCompoundPaddingRight();\n    }\n\n    /***\n     * @param text  文本\n     * @param paint 画笔\n     * @return 文本布局\n     */\n    public StaticLayout getStaticLayout(CharSequence text, TextPaint paint) {\n        return getStaticLayout(textView.getTextView(), text, paint);\n    }\n\n    /**\n     * @param textView 文本框\n     * @param text     文本\n     * @param paint    画笔\n     * @return 文本布局\n     */\n    public static StaticLayout getStaticLayout(TextView textView, CharSequence text, TextPaint paint) {\n        StaticLayout layout;\n        if (textView instanceof FitTextView) {\n            FitTextView fitTextView = (FitTextView) textView;\n            layout = new StaticLayout(text, paint, getTextWidth(textView),\n                    getLayoutAlignment(fitTextView), fitTextView.getLineSpacingMultiplierCompat(),\n                    fitTextView.getLineSpacingExtraCompat(), fitTextView.getIncludeFontPaddingCompat());\n        } else {\n            if (Build.VERSION.SDK_INT <= 16) {\n                layout = new StaticLayout(text, paint, getTextWidth(textView),\n                        getLayoutAlignment(textView), 0, 0, false);\n            } else {\n                layout = new StaticLayout(text, paint, getTextWidth(textView),\n                        getLayoutAlignment(textView), textView.getLineSpacingMultiplier(),\n                        textView.getLineSpacingExtra(), textView.getIncludeFontPadding());\n            }\n        }\n        if(isSingleLine(textView)) {\n            try {\n                Field field = StaticLayout.class.getDeclaredField(\"mMaximumVisibleLineCount\");\n                if (field != null) {\n                    field.setAccessible(true);\n                    field.set(layout, 1);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return layout;\n    }\n\n    /**\n     * 判断内容是否在框内\n     *\n     * @param text  文本\n     * @param paint 画笔\n     * @return 没有超过框\n     */\n    protected boolean isFit(CharSequence text, TextPaint paint) {\n        // 自动换行\n        boolean mSingleLine = textView.isSingleLine();\n        int maxLines = textView.getMaxLinesCompat();\n        float multi = textView.getLineSpacingMultiplierCompat();\n        float space = textView.getLineSpacingExtraCompat();\n        space = space * multi;\n        int height = textView.getTextHeight();\n        if (!mSingleLine) {\n            if (!LastNoSpace) {\n                height += Math.round(space);\n            }\n        }\n\n        int lines = mSingleLine ? 1 : Math.max(1, maxLines);\n\n        StaticLayout layout = getStaticLayout(text, paint);\n\n        return layout.getLineCount() <= lines && layout.getHeight() <= height;\n    }\n\n    /**\n     * 调整字体大小\n     *\n     * @param oldPaint 旧画笔\n     * @param text     内容\n     * @param max      最大字体\n     * @param min      最小字体\n     * @return 适合字体大小\n     */\n    public float fitTextSize(TextPaint oldPaint, CharSequence text, float max, float min) {\n        if (TextUtils.isEmpty(text)) {\n            if (oldPaint != null) {\n                return oldPaint.getTextSize();\n            }\n            if (textView != null) {\n                return textView.getTextSize();\n            }\n        }\n        float low = min;\n        float high = max;\n        TextPaint paint = new TextPaint(oldPaint);\n        while (Math.abs(high - low) > LIMIT) {\n            paint.setTextSize((low + high) / 2.0f);\n            if (isFit(getLineBreaks(text, paint), paint)) {\n                low = paint.getTextSize();\n            } else {\n                high = paint.getTextSize();\n            }\n        }\n        return low;\n    }\n\n    /**\n     * 拆入换行符，解决中英文的换行问题\n     *\n     * @param text  内容\n     * @param paint 画笔\n     * @return 调整后的内容\n     */\n    public CharSequence getLineBreaks(\n            CharSequence text, TextPaint paint) {\n        int width = textView.getTextWidth();\n        boolean keepWord = textView.isKeepWord();\n        if (width <= 0 || keepWord)\n            return text;\n        int length = text.length();\n        int start = 0, end = 1;\n\n        SpannableStringBuilder ssb = new SpannableStringBuilder();\n        while (end <= length) {\n            CharSequence c = text.subSequence(end - 1, end);\n//            char c = text.charAt(end - 1);// cs最后一个字符\n//            boolean needCheck = false;\n            if (TextUtils.equals(c, \"\\n\")) {// 已经换行\n                ssb.append(text, start, end);\n                start = end;\n//                needCheck = true;\n            } else {\n                float lw = paint.measureText(text, start, end);\n                if (lw > width) {// 超出宽度，退回一个位置\n                    ssb.append(text, start, end - 1);\n                    start = end - 1;\n                    if (end < length) {\n                        CharSequence c2 = text.subSequence(end - 1, end);\n                        if (!TextUtils.equals(c2, \"\\n\"))\n                            ssb.append('\\n');\n                    }\n//                    needCheck = true;\n                } else if (lw == width) {\n                    ssb.append(text, start, end);\n                    start = end;\n                    if (end < length) {\n                        CharSequence c2 = text.subSequence(end, end + 1);\n                        if (!TextUtils.equals(c2, \"\\n\"))\n                            ssb.append('\\n');\n                    }\n//                    needCheck = true;\n                } else if (end == length) {\n                    // 已经是最后一个字符\n                    ssb.append(text, start, end);\n                    start = end;\n                }\n            }\n            end++;\n        }\n        return ssb;\n    }\n\n    /***\n     * 获取文本框的布局\n     *\n     * @param textView\n     * @return\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\n    public static Layout.Alignment getLayoutAlignment(TextView textView) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            return Layout.Alignment.ALIGN_NORMAL;\n        }\n\n        Layout.Alignment alignment;\n        switch (textView.getTextAlignment()) {\n            case TextView.TEXT_ALIGNMENT_GRAVITY:\n                switch (textView.getGravity() & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {\n                    case Gravity.START:\n                        alignment = Layout.Alignment.ALIGN_NORMAL;\n                        break;\n                    case Gravity.END:\n                        alignment = Layout.Alignment.ALIGN_OPPOSITE;\n                        break;\n                    case Gravity.LEFT:\n                        alignment = (textView.getLayoutDirection() == TextView.LAYOUT_DIRECTION_RTL) ? Layout.Alignment.ALIGN_OPPOSITE\n                                : Layout.Alignment.ALIGN_NORMAL;\n                        break;\n                    case Gravity.RIGHT:\n                        alignment = (textView.getLayoutDirection() == TextView.LAYOUT_DIRECTION_RTL) ? Layout.Alignment.ALIGN_NORMAL\n                                : Layout.Alignment.ALIGN_OPPOSITE;\n                        break;\n                    case Gravity.CENTER_HORIZONTAL:\n                        alignment = Layout.Alignment.ALIGN_CENTER;\n                        break;\n                    default:\n                        alignment = Layout.Alignment.ALIGN_NORMAL;\n                        break;\n                }\n                break;\n            case TextView.TEXT_ALIGNMENT_TEXT_START:\n                alignment = Layout.Alignment.ALIGN_NORMAL;\n                break;\n            case TextView.TEXT_ALIGNMENT_TEXT_END:\n                alignment = Layout.Alignment.ALIGN_OPPOSITE;\n                break;\n            case TextView.TEXT_ALIGNMENT_CENTER:\n                alignment = Layout.Alignment.ALIGN_CENTER;\n                break;\n            case TextView.TEXT_ALIGNMENT_VIEW_START:\n                alignment = Layout.Alignment.ALIGN_NORMAL;\n                break;\n            case TextView.TEXT_ALIGNMENT_VIEW_END:\n                alignment = Layout.Alignment.ALIGN_OPPOSITE;\n                break;\n            case TextView.TEXT_ALIGNMENT_INHERIT:\n                //\n            default:\n                alignment = Layout.Alignment.ALIGN_NORMAL;\n                break;\n        }\n        return alignment;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/app/src/main/java/io/virtualapp/widgets/fittext/FitTextView.java",
    "content": "package io.virtualapp.widgets.fittext;\n\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.text.TextPaint;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport io.virtualapp.R;\n\npublic class FitTextView extends BaseTextView {\n\n    private boolean mMeasured = false;\n    /**\n     * 不需要调整大小\n     */\n    private boolean mNeedFit = true;\n    protected float mOriginalTextSize = 0;\n    private float mMinTextSize, mMaxTextSize;\n    protected CharSequence mOriginalText;\n    /**\n     * 正在调整字体大小\n     */\n    protected volatile boolean mFittingText = false;\n    protected FitTextHelper mFitTextHelper;\n\n    public FitTextView(Context context) {\n        this(context, null);\n    }\n\n    public FitTextView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public FitTextView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        mOriginalTextSize = getTextSize();\n        if (attrs != null) {\n            TypedArray a = context.obtainStyledAttributes(attrs, new int[]{\n                    R.attr.ftMaxTextSize,\n                    R.attr.ftMinTextSize,\n                    });\n            mMaxTextSize = a.getDimension(0, mOriginalTextSize * 2.0f);\n            mMinTextSize = a.getDimension(1, mOriginalTextSize / 2.0f);\n            a.recycle();\n        } else {\n            mMinTextSize = mOriginalTextSize;\n            mMaxTextSize = mOriginalTextSize;\n        }\n    }\n\n    protected FitTextHelper getFitTextHelper() {\n        if (mFitTextHelper == null) {\n            mFitTextHelper = new FitTextHelper(this);\n        }\n        return mFitTextHelper;\n    }\n\n    /**\n     * @return 最小字体大小\n     */\n    public float getMinTextSize() {\n        return mMinTextSize;\n    }\n\n    /**\n     * @param minTextSize 最小字体大小\n     */\n    public void setMinTextSize(float minTextSize) {\n        mMinTextSize = minTextSize;\n    }\n\n    /**\n     * @return 最大字体大小\n     */\n    public float getMaxTextSize() {\n        return mMaxTextSize;\n    }\n\n    /**\n     * @param maxTextSize 最大字体大小\n     */\n    public void setMaxTextSize(float maxTextSize) {\n        mMaxTextSize = maxTextSize;\n    }\n\n    /**\n     * 是否需要调整字体\n     *\n     * @return\n     */\n    public boolean isNeedFit() {\n        return mNeedFit;\n    }\n\n    /**\n     * @param needFit 是否需要调整字体大小\n     */\n    public void setNeedFit(boolean needFit) {\n        mNeedFit = needFit;\n    }\n\n    @Override\n    public void setTextSize(int unit, float size) {\n        super.setTextSize(unit, size);\n        mOriginalTextSize = getTextSize();\n    }\n\n    public float getOriginalTextSize() {\n        return mOriginalTextSize;\n    }\n\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);\n        int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);\n\n        if (widthMode == View.MeasureSpec.UNSPECIFIED\n                && heightMode == View.MeasureSpec.UNSPECIFIED) {\n            super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOriginalTextSize);\n            mMeasured = false;\n        } else {\n            mMeasured = true;\n            fitText(getOriginalText());\n        }\n    }\n\n    @Override\n    public void setText(CharSequence text, TextView.BufferType type) {\n        mOriginalText = text;\n        super.setText(text, type);\n        fitText(text);\n    }\n\n    public CharSequence getOriginalText() {\n        return mOriginalText;\n    }\n\n    /**\n     * 调整字体大小\n     *\n     * @param text 内容\n     */\n    protected void fitText(CharSequence text) {\n        if (!mNeedFit) {\n            return;\n        }\n        if (!mMeasured || mFittingText || mSingleLine || TextUtils.isEmpty(text))\n            return;\n        mFittingText = true;\n        TextPaint oldPaint = getPaint();\n        float size = getFitTextHelper().fitTextSize(oldPaint, text, mMaxTextSize, mMinTextSize);\n        super.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);\n        super.setText(getFitTextHelper().getLineBreaks(text, getPaint()));\n        mFittingText = false;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n    }\n\n}"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/blue_circle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\" >\n\n    <solid android:color=\"#03a9f4\" />\n\n    <corners android:radius=\"5dip\" />\n\n</shape>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/fab_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\">\n        <layer-list>\n            <!-- Shadow -->\n            <item android:right=\"1dp\" android:top=\"1dp\">\n                <layer-list>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#08000000\"/>\n                            <padding\n                                android:bottom=\"3px\"\n                                android:left=\"3px\"\n                                android:right=\"3px\"\n                                android:top=\"3px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#09000000\"/>\n                            <padding\n                                android:bottom=\"2px\"\n                                android:left=\"2px\"\n                                android:right=\"2px\"\n                                android:top=\"2px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#10000000\"/>\n                            <padding\n                                android:bottom=\"2px\"\n                                android:left=\"2px\"\n                                android:right=\"2px\"\n                                android:top=\"2px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#11000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#12000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#13000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#14000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#15000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#16000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                </layer-list>\n            </item>\n\n            <!-- Blue button pressed -->\n            <item>\n                <shape android:shape=\"oval\">\n                    <solid android:color=\"#90CAF9\"/>\n                </shape>\n            </item>\n        </layer-list>\n    </item>\n\n    <item android:state_enabled=\"true\">\n\n        <layer-list>\n            <!-- Shadow -->\n            <item android:right=\"1dp\" android:top=\"2dp\">\n                <layer-list>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#08000000\"/>\n                            <padding\n                                android:bottom=\"4px\"\n                                android:left=\"4px\"\n                                android:right=\"4px\"\n                                android:top=\"4px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#09000000\"/>\n                            <padding\n                                android:bottom=\"2px\"\n                                android:left=\"2px\"\n                                android:right=\"2px\"\n                                android:top=\"2px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#10000000\"/>\n                            <padding\n                                android:bottom=\"2px\"\n                                android:left=\"2px\"\n                                android:right=\"2px\"\n                                android:top=\"2px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#11000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#12000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#13000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#14000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#15000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                    <item>\n                        <shape android:shape=\"oval\">\n                            <solid android:color=\"#16000000\"/>\n                            <padding\n                                android:bottom=\"1px\"\n                                android:left=\"1px\"\n                                android:right=\"1px\"\n                                android:top=\"1px\"\n                                />\n                        </shape>\n                    </item>\n                </layer-list>\n            </item>\n\n            <!-- Blue button -->\n\n            <item>\n                <shape android:shape=\"oval\">\n                    <solid android:color=\"#03A9F4\"/>\n                </shape>\n            </item>\n        </layer-list>\n\n    </item>\n\n</selector>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/home_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:angle=\"0\"\n        android:endColor=\"#0a2746\"\n        android:startColor=\"#21263d\"/>\n</shape>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/icon_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@color/black_20_transparent\"/>\n    <item android:drawable=\"@color/transparent\"/>\n</selector>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/sel_clone_app_btn.xml",
    "content": "<selector xmlns:Android=\"http://schemas.android.com/apk/res/android\">\n\n\n    <item Android:drawable=\"@drawable/shape_clone_app_btn\" Android:state_pressed=\"true\"/>\n    <item Android:drawable=\"@drawable/shape_clone_app_btn_pressed\"/>\n\n\n</selector>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/sel_guide_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:shape=\"rectangle\">\n    <corners\n        android:radius=\"25dp\"\n        />\n    <solid\n        android:color=\"@color/colorPrimaryDark\"\n        />\n    <padding\n        android:bottom=\"0dp\"\n        android:left=\"0dp\"\n        android:right=\"0dp\"\n        android:top=\"0dp\"\n        />\n</shape>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/shape_clone_app_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <solid android:color=\"#03a9f4\" />\n    <corners android:radius=\"5dip\" />\n</shape>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable/shape_clone_app_btn_pressed.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <solid android:color=\"#0083be\" />\n    <corners android:radius=\"5dip\" />\n</shape>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable-nodpi/about_icon_copy_right.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n    <path\n        android:fillColor=\"#000000\"\n        android:pathData=\"M10.08,10.86c0.05,-0.33 0.16,-0.62 0.3,-0.87s0.34,-0.46 0.59,-0.62c0.24,-0.15 0.54,-0.22 0.91,-0.23 0.23,0.01 0.44,0.05 0.63,0.13 0.2,0.09 0.38,0.21 0.52,0.36s0.25,0.33 0.34,0.53 0.13,0.42 0.14,0.64h1.79c-0.02,-0.47 -0.11,-0.9 -0.28,-1.29s-0.4,-0.73 -0.7,-1.01 -0.66,-0.5 -1.08,-0.66 -0.88,-0.23 -1.39,-0.23c-0.65,0 -1.22,0.11 -1.7,0.34s-0.88,0.53 -1.2,0.92 -0.56,0.84 -0.71,1.36S8,11.29 8,11.87v0.27c0,0.58 0.08,1.12 0.23,1.64s0.39,0.97 0.71,1.35 0.72,0.69 1.2,0.91 1.05,0.34 1.7,0.34c0.47,0 0.91,-0.08 1.32,-0.23s0.77,-0.36 1.08,-0.63 0.56,-0.58 0.74,-0.94 0.29,-0.74 0.3,-1.15h-1.79c-0.01,0.21 -0.06,0.4 -0.15,0.58s-0.21,0.33 -0.36,0.46 -0.32,0.23 -0.52,0.3c-0.19,0.07 -0.39,0.09 -0.6,0.1 -0.36,-0.01 -0.66,-0.08 -0.89,-0.23 -0.25,-0.16 -0.45,-0.37 -0.59,-0.62s-0.25,-0.55 -0.3,-0.88 -0.08,-0.67 -0.08,-1v-0.27c0,-0.35 0.03,-0.68 0.08,-1.01zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z\" />\n</vector>"
  },
  {
    "path": "VirtualApp/app/src/main/res/drawable-nodpi/ic_more.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"32dp\"\n    android:width=\"32dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path android:fillColor=\"#7f000000\" android:pathData=\"M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z\" />\n</vector>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_clone_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/clone_app_tool_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\">\n\n        <android.support.design.widget.TabLayout\n            android:id=\"@+id/clone_app_tab_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            app:tabMode=\"scrollable\" />\n\n    </android.support.v7.widget.Toolbar>\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/clone_app_view_pager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n</LinearLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_install.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"10dp\">\n\n    <TextView\n        android:id=\"@+id/installer_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentTop=\"true\"\n        android:textColor=\"#000000\"\n        android:textSize=\"18sp\"\n        tools:text=\"install new version?\" />\n\n    <TextView\n        android:id=\"@+id/installer_progress_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:textColor=\"#000000\"\n        android:visibility=\"invisible\" />\n\n    <ProgressBar\n        android:id=\"@+id/installer_loading\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@id/installer_progress_text\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"10dp\"\n        android:visibility=\"gone\" />\n\n    <Button\n        android:id=\"@+id/installer_right_button\"\n        style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentRight=\"true\" />\n\n    <Button\n        android:id=\"@+id/installer_left_button\"\n        style=\"@style/Widget.AppCompat.Button.Borderless.Colored\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_toLeftOf=\"@id/installer_right_button\" />\n\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:fab=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@+id/list\"\n        style=\"@style/Widget.AppCompat.ListView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:id=\"@+id/empty_view\"\n        android:gravity=\"center\"\n        android:textSize=\"18sp\"\n        android:textColor=\"#000000\"\n        android:visibility=\"gone\"\n        android:text=\"No Data\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n</LinearLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/transparent\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"128dp\"\n        android:layout_gravity=\"bottom\"\n        android:background=\"#F8F8F8\">\n\n        <io.virtualapp.widgets.EatBeansView\n            android:id=\"@+id/loading_anim\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"30dp\" />\n\n        <ImageView\n            android:id=\"@+id/app_icon\"\n            android:layout_width=\"64dp\"\n            android:layout_height=\"64dp\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"64dp\"\n            android:layout_marginStart=\"64dp\" />\n\n\n        <TextView\n            android:id=\"@+id/app_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignBottom=\"@id/app_icon\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_toEndOf=\"@id/app_icon\"\n            android:layout_toRightOf=\"@id/app_icon\"\n            android:gravity=\"center\"\n            android:paddingBottom=\"25dp\"\n            android:text=\"@string/preparing\"\n            android:textColor=\"@android:color/black\" />\n\n    </RelativeLayout>\n\n</FrameLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_location_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:orientation=\"vertical\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\">\n\n    <ListView\n        android:id=\"@+id/appdata_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n</LinearLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_marker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:clipToPadding=\"true\"\n    android:fitsSystemWindows=\"true\"\n    >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <include layout=\"@layout/content_toolbar\"/>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <io.virtualapp.widgets.fittext.FitTextView\n                android:id=\"@+id/address\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"@dimen/line_height\"\n                android:layout_marginLeft=\"6dp\"\n                android:layout_marginRight=\"6dp\"\n                android:gravity=\"center_vertical\"\n                android:maxLines=\"2\"\n                app:ftMaxTextSize=\"20sp\"\n                app:ftMinTextSize=\"10sp\"\n                tools:text=\"hello\"/>\n\n            <com.tencent.tencentmap.mapsdk.map.MapView\n                android:id=\"@+id/map\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"fill_parent\" />\n        </LinearLayout>\n    </LinearLayout>\n</android.support.design.widget.CoordinatorLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_splash.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"bottom\"\n    android:orientation=\"vertical\"\n    tools:context=\".splash.SplashActivity\">\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|center\"\n        android:layout_marginBottom=\"20dp\"\n        android:text=\"@string/app_name\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"26sp\" />\n\n\n</LinearLayout>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/activity_users.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:orientation=\"vertical\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\">\n\n    <com.yanzhenjie.recyclerview.swipe.SwipeMenuRecyclerView\n        android:layout_marginTop=\"10dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:id=\"@+id/user_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n</LinearLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/content_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.AppBarLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/task_top_toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:background=\"@color/colorPrimary\"\n        app:popupTheme=\"@style/AppTheme.PopupOverlay\"\n        app:theme=\"@style/AppTheme.AppBarOverlay\"/>\n</android.support.design.widget.AppBarLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/fragment_list_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <io.virtualapp.widgets.DragSelectRecyclerView\n        android:id=\"@+id/select_app_recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"vertical\"\n        app:dsrv_autoScrollEnabled=\"false\" />\n\n    <ProgressBar\n        android:id=\"@+id/select_app_progress_bar\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\" />\n\n    <Button\n        android:id=\"@+id/select_app_install_btn\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_gravity=\"bottom|center\"\n        android:layout_margin=\"15dp\"\n        android:background=\"@drawable/sel_clone_app_btn\"\n        android:text=\"@string/list_app_activity_install\"\n        android:textColor=\"@color/desktopColorB\"\n        android:textSize=\"17sp\"\n        tools:ignore=\"HardcodedText\" />\n\n    <android.support.design.widget.FloatingActionButton\n        android:id=\"@+id/select_app_from_external\"\n        android:src=\"@drawable/ic_add\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_marginBottom=\"100dp\"\n        android:layout_marginRight=\"40dp\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n</FrameLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/selectableItemBackground\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/item_app_icon\"\n            android:layout_width=\"60dp\"\n            android:layout_height=\"60dp\"\n            tools:src=\"@mipmap/ic_launcher\"\n            />\n\n        <TextView\n            android:id=\"@+id/item_app_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            tools:text=\"App Label\"\n            android:gravity=\"center|start\" />\n\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_app_manage.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/item_app_icon\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_alignParentStart=\"true\"\n            android:layout_centerVertical=\"true\"\n            tools:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            android:id=\"@+id/item_app_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_toRightOf=\"@+id/item_app_icon\"\n            android:gravity=\"center|left\"\n            tools:text=\"App Label\" />\n\n        <ImageView\n            android:id=\"@+id/item_app_button\"\n            android:src=\"@drawable/ic_more\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerVertical=\"true\" />\n    </RelativeLayout>\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_clone_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:id=\"@+id/item_app_checked\"\n        android:layout_width=\"23dp\"\n        android:layout_height=\"23dp\"\n        android:layout_gravity=\"top|end\"\n        android:src=\"@drawable/ic_no_check\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start|center\"\n        android:gravity=\"start|center\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"24dp\"\n        android:paddingTop=\"12dp\"\n        android:paddingBottom=\"12dp\">\n\n        <ImageView\n            android:id=\"@+id/item_app_icon\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"start|center\"\n            android:orientation=\"vertical\"\n            android:paddingLeft=\"10dp\">\n\n            <TextView\n                android:id=\"@+id/item_app_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:ellipsize=\"marquee\"\n                android:focusableInTouchMode=\"true\"\n                android:gravity=\"center\"\n                android:marqueeRepeatLimit=\"marquee_forever\"\n                android:singleLine=\"true\"\n                android:textColor=\"@color/desktopColorB\"\n                android:textSize=\"14sp\" />\n\n        </LinearLayout>\n    </LinearLayout>\n\n    <io.virtualapp.widgets.LabelView xmlns:lv=\"http://schemas.android.com/apk/res-auto\"\n        android:id=\"@+id/item_app_clone_count\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|start\"\n        android:visibility=\"invisible\"\n        lv:lv_background_color=\"#F6CE59\"\n        lv:lv_fill_triangle=\"true\"\n        lv:lv_gravity=\"BOTTOM_LEFT\"\n        lv:lv_text=\"2\"\n        lv:lv_text_all_caps=\"false\"\n        lv:lv_text_color=\"@android:color/white\"\n        lv:lv_text_size=\"12sp\" />\n\n</FrameLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_location_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:background=\"?attr/selectableItemBackground\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/item_app_icon\"\n            android:layout_width=\"60dp\"\n            android:layout_height=\"60dp\"\n            tools:src=\"@mipmap/ic_launcher\"\n            />\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/item_app_name\"\n                style=\"@style/TextAppearance.AppCompat.Body1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_marginLeft=\"20dp\"\n                android:layout_marginStart=\"20dp\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center|start\"\n                tools:text=\"App Label\"/>\n\n            <TextView\n                android:id=\"@+id/item_location\"\n                style=\"@style/TextAppearance.AppCompat.Caption\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_marginLeft=\"20dp\"\n                android:layout_marginStart=\"20dp\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center|start\"\n                tools:text=\"22,114\"/>\n\n        </LinearLayout>\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_plugin_recommend.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"start|center\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"14dp\"\n    android:paddingLeft=\"18dp\"\n    android:paddingTop=\"14dp\">\n\n    <TextView\n        android:id=\"@+id/item_plugin_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"4dp\"\n        android:ellipsize=\"marquee\"\n        android:gravity=\"start|center\"\n        android:textColor=\"@color/desktopColorB\"\n        android:textSize=\"16sp\" />\n\n    <TextView\n        android:id=\"@+id/item_plugin_summary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/item_plugin_name\"\n        android:gravity=\"start|center\"\n        android:textSize=\"12sp\" />\n</RelativeLayout>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_share.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"10dp\"\n    android:background=\"?attr/selectableItemBackground\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"54dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/item_share_icon\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\"\n            tools:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            android:id=\"@+id/item_share_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginStart=\"10dp\"\n            android:gravity=\"center|start\"\n            tools:text=\"App Label\" />\n\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_task_manage.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/item_app_icon\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_alignParentStart=\"true\"\n            android:layout_centerVertical=\"true\"\n            tools:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            android:id=\"@+id/item_app_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_toRightOf=\"@+id/item_app_icon\"\n            android:gravity=\"center|left\"\n            tools:text=\"App Label\" />\n\n        <Button\n            android:id=\"@+id/item_app_button\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerVertical=\"true\" />\n    </RelativeLayout>\n</RelativeLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/layout/item_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"60dp\"\n              android:background=\"?selectableItemBackground\"\n              android:gravity=\"center_vertical\"\n              android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/iv_icon\"\n        android:layout_width=\"60dp\"\n        android:layout_height=\"60dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"10dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "VirtualApp/app/src/main/res/menu/app_manage_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_uninstall\"\n        android:orderInCategory=\"100\"\n        android:title=\"@string/app_manage_uninstall\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/action_repair\"\n        android:orderInCategory=\"100\"\n        android:title=\"@string/app_manage_repair\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/action_redirect\"\n        android:orderInCategory=\"100\"\n        android:title=\"@string/app_manage_redirect_on\"\n        app:showAsAction=\"withText\" />\n</menu>"
  },
  {
    "path": "VirtualApp/app/src/main/res/menu/main_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_settings\"\n        android:orderInCategory=\"100\"\n        app:showAsAction=\"always\"\n        android:title=\"@string/settings_title\"\n        android:icon=\"@drawable/ic_add\"/>\n</menu>"
  },
  {
    "path": "VirtualApp/app/src/main/res/menu/marktet_map.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_clear\"\n        android:title=\"Clear\"\n        app:showAsAction=\"always\"/>\n    <item\n        android:id=\"@+id/action_ok\"\n        android:title=\"@android:string/ok\"\n        app:showAsAction=\"always\"/>\n</menu>"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"CardStackLayout\">\n        <attr name=\"parallax_enabled\" format=\"boolean\" />\n        <attr name=\"parallax_scale\" format=\"integer\" />\n        <attr name=\"card_gap\" format=\"dimension\" />\n        <attr name=\"card_gap_bottom\" format=\"dimension\" />\n        <attr name=\"showInitAnimation\" format=\"boolean\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"ProgressImageView\">\n        <attr name=\"pi_progress\" format=\"integer\" />\n        <attr name=\"pi_mask_color\" format=\"color\" />\n        <attr name=\"pi_stroke\" format=\"dimension\" />\n        <attr name=\"pi_radius\" format=\"dimension\" />\n        <attr name=\"pi_force_square\" format=\"boolean\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"ShimmerView\">\n        <attr name=\"reflectionColor\" format=\"color\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"DragSelectRecyclerView\">\n        <attr name=\"dsrv_autoScrollHotspotHeight\" format=\"dimension\" />\n        <attr name=\"dsrv_autoScrollEnabled\" format=\"boolean\" />\n        <attr name=\"dsrv_autoScrollHotspot_offsetTop\" format=\"dimension\" />\n        <attr name=\"dsrv_autoScrollHotspot_offsetBottom\" format=\"dimension\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"LabelView\">\n        <!-- 设置文字内容 -->\n        <attr name=\"lv_text\" format=\"string\"/>\n        <!-- 设置文字颜色,默认#ffffff -->\n        <attr name=\"lv_text_color\" format=\"color\"/>\n        <!-- 设置文字大小,默认11sp -->\n        <attr name=\"lv_text_size\" format=\"dimension\"/>\n        <!-- 设置文字是否支持加粗,默认true -->\n        <attr name=\"lv_text_bold\" format=\"boolean\"/>\n        <!-- 设置文字是否支持全部大写,默认true-->\n        <attr name=\"lv_text_all_caps\" format=\"boolean\"/>\n        <!-- 设置背景颜色,默认\"#FF4081\"-->\n        <attr name=\"lv_background_color\" format=\"color\"/>\n        <!-- 设置LabelView所在矩形最小宽高,默认mFillTriangle?35dp:50dp-->\n        <attr name=\"lv_min_size\" format=\"dimension\"/>\n        <!-- 设置文字上下padding,默认3.5dp,mFillTriangle为true时无效-->\n        <attr name=\"lv_padding\" format=\"dimension\"/>\n        <!-- 设置LabelView方向 -->\n        <attr name=\"lv_gravity\" format=\"enum\">\n            <enum name=\"TOP_LEFT\" value=\"51\"/>\n            <enum name=\"TOP_RIGHT\" value=\"53\"/>\n            <enum name=\"BOTTOM_LEFT\" value=\"83\"/>\n            <enum name=\"BOTTOM_RIGHT\" value=\"85\"/>\n        </attr>\n        <!-- 设置是否填充三角区域,默认false -->\n        <attr name=\"lv_fill_triangle\" format=\"boolean\"/>\n\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#607191</color>\n    <color name=\"colorPrimaryDark\">#2A364C</color>\n    <color name=\"colorPrimaryRavel\">#607191</color>\n    <color name=\"colorAccent\">#607191</color>\n    <color name=\"mainTextColor\">#F0DEB7</color>\n\n    <color name=\"desktopColorA\">#2C3B4E</color>\n    <color name=\"desktopColorB\">#314155</color>\n    <color name=\"desktopColorC\">#324257</color>\n    <color name=\"desktopColorD\">#2a3646</color>\n    <color name=\"desktopColorE\">#11000000</color>\n\n    <color name=\"holo_blue_dark\">#33cccc</color>\n    <color name=\"holo_yellow_dark\">#ff9640</color>\n    <color name=\"holo_green_dark\">#67e667</color>\n    <color name=\"holo_purple_dark\">#df38b1</color>\n    <color name=\"holo_red_dark\">#ff4040</color>\n\n    <integer-array name=\"progress_colors\">\n        <item>@color/holo_blue_dark</item>\n        <item>@color/holo_yellow_dark</item>\n        <item>@color/holo_green_dark</item>\n        <item>@color/holo_purple_dark</item>\n        <item>@color/holo_red_dark</item>\n    </integer-array>\n\n    <color name=\"transparent\">#00000000</color>\n    <color name=\"black_20_transparent\">#55000000</color>\n\n    <color name=\"md_transparent\">#00FFFFFF</color>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n    <!--Card Stack-->\n    <dimen name=\"card_gap\">60dp</dimen>\n    <dimen name=\"card_gap_bottom\">5dp</dimen>\n    <dimen name=\"dp30\">30dp</dimen>\n    <dimen name=\"dp8\">8dp</dimen>\n    <dimen name=\"dp10\">10dp</dimen>\n    <dimen name=\"dp80\">80dp</dimen>\n    <dimen name=\"card_radius\">5dp</dimen>\n    <dimen name=\"dp16\">16dp</dimen>\n    <dimen name=\"dp24\">24dp</dimen>\n\n    <!--Desktop-->\n    <dimen name=\"desktop_divider\">0.5dp</dimen>\n    <dimen name=\"item_height\">60dp</dimen>\n\n    <dimen name=\"dsrv_defaultHotspotHeight\">56dp</dimen>\n    <dimen name=\"line_height\">40dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/fitTextView.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"FitTextView\">\n        <attr name=\"ftMinTextSize\" format=\"dimension\"/>\n        <attr name=\"ftMaxTextSize\" format=\"dimension\"/>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/ids.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <item name=\"cardstack_internal_position_tag\" type=\"id\"/>\n</resources>"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <integer name=\"parallax_scale_default\">-2</integer>\n</resources>"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <!--<string name=\"app_name\">VirtualApp</string>-->\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"vxp\">VirtualXposed</string>\n    <string name=\"wait\">Please wait…</string>\n    <string name=\"desktop\">Desktop</string>\n    <string name=\"add_app\">Add App</string>\n    <string name=\"preparing\">Opening app…</string>\n    <string name=\"delete\">Delete</string>\n    <string name=\"create_shortcut\">Create shortcut</string>\n    <string name=\"new_user\">New User</string>\n    <string name=\"enable\">Enable</string>\n    <string name=\"save\">Save</string>\n    <string name=\"save_success\">Save successful!</string>\n    <string name=\"manufacturer\">Manufacturer</string>\n    <string name=\"brand\">Brand</string>\n    <string name=\"device\">Device</string>\n    <string name=\"fake_device_info\">Fake Device Info</string>\n    <string name=\"wifi_status\">Wifi Status</string>\n    <string name=\"config_device_info\">Device Info</string>\n    <string name=\"about\">About</string>\n    <string name=\"clone_apps\">Clone Apps</string>\n    <string name=\"external_storage\">External Storage</string>\n    <string name=\"install_d\">Install (%d)</string>\n    <string name=\"install_too_much_once_time\">You may choose no more than 9 apps at once!</string>\n    <string name=\"versionchecklib_confirm\">Download</string>\n    <string name=\"versionchecklib_cancel\">Cancel</string>\n    <string name=\"menu_virtual_location\">Virtual Location</string>\n    <string name=\"menu_about\">About</string>\n    <string name=\"menu_reboot\">Reboot</string>\n    <string name=\"installing_tips\">Installing %1$s…</string>\n    <string name=\"update_success_tips\">Update %1$s success!</string>\n    <string name=\"install_success_tips\">The Xposed module will not take effect until you enable it in XposedInstaller\\'s module setting.</string>\n    <string name=\"install_fail_tips\">Install %1$s failed: %2$s</string>\n    <string name=\"copy_right\" translatable=\"false\" >Copyright © %1$d</string>\n    <string name=\"about_page_description\">VirtualXposed is an app that provides the ability to use the Xposed module without needing root access, unlocking the bootloader, or modifying the system image.</string>\n    <string name=\"about_feedback_qq_title\">QQ Group (Click to copy group number)</string>\n    <string name=\"about_feedback_wechat_title\">WeChat Group (Click to copy)</string>\n    <string name=\"about_feedback_tips\">Group number has been copied to clipboard!</string>\n    <string name=\"about_version_title\">Version: %1$s</string>\n    <string name=\"about_donate_title\">Donate</string>\n    <string name=\"reboot_tips_1\">Reboot successfully!</string>\n    <string name=\"reboot_tips_2\">Reboot successfully!</string>\n    <string name=\"reboot_tips_3\">Reboot successfully!</string>\n    <string name=\"meizu_device_tips_title\">Detect Meizu Device: </string>\n    <string name=\"meizu_device_tips_content\">In Meizu OS phones, you can only add an app to VirtualXposed by cloning an existing app that\\'s already installed (you cannot install an app in VirtualXposed via sideloading an apk). You must also install XposedInstaller manually, as, unlike installations on other Android phones, it isn\\'t built in to VirtualXposed when installing on Meizu OS. Please install XposedInstaller first.</string>\n    <string name=\"donate_alipay\">Alipay</string>\n    <string name=\"donate_wepay\">Wechat Pay</string>\n    <string name=\"prompt_alipay_not_found\">Alipay not found.</string>\n    <string name=\"prompt_wait\">Wait just a moment…</string>\n    <string name=\"donate_dialog_title\">About Donate</string>\n    <string name=\"donate_dialog_content\">The maintaining of VirtualXposed costs lots of my time, if you appreciate my work, buy me a cup of coffee! :)</string>\n    <string name=\"donate_dialog_yes\">Donate</string>\n    <string name=\"donate_dialog_no\">Cancel</string>\n    <string name=\"large_app_install_tips\">Installation may take a while, please be patient… :)</string>\n    <string name=\"about_icon_title\">About Icon</string>\n    <string name=\"about_icon_content\">If you do not like my new icon, you are always welcome to design a new icon for VirtualXposed ;)</string>\n    <string name=\"about_icon_yes\">OK</string>\n    <string name=\"create_shortcut_success\">Shortcut created!</string>\n    <string name=\"about_thanks\">Credits</string>\n    <string name=\"thanks_dialog_title\">Credits</string>\n    <string name=\"thanks_dialog_content\" >Thanks Cheney for providing the awesome icon, and thank you Pei, Peggy, and too many others to list, for your hard work. Thanks for the ideas and suggestions you all provided, and special thanks to YingLin for taking the time to help me achieve my design :)</string>\n    <string name=\"alert_for_doze_mode_title\">Tips</string>\n    <string name=\"alert_for_doze_mode_content\">Please allow VirtualXposed to run in the background, otherwise you may not receive notifications from some virtual apps.</string>\n    <string name=\"alert_for_doze_mode_yes\">Allow</string>\n    <string name=\"alert_for_doze_mode_no\">Deny</string>\n    <string name=\"about_faq_title\">FAQ</string>\n    <string name=\"clear_app\">Clear\\nData</string>\n    <string name=\"stop_app\">Force\\nStop</string>\n    <string name=\"home_menu_delete_title\">Delete App</string>\n    <string name=\"home_menu_delete_content\">Do you want to delete %1$s ?</string>\n    <string name=\"home_menu_clear_title\" >Clear App Data</string>\n    <string name=\"home_menu_clear_content\" >Do you want to clear data of %1$s ?</string>\n    <string name=\"home_menu_kill_title\">Force Stop</string>\n    <string name=\"home_menu_kill_content\">Do you want to force stop %1$s ? This may cause unexpected app behaviours. </string>\n    <string name=\"add_app_loading_tips\">Parsing package for %1$s…</string>\n    <string name=\"add_app_installing_tips\">Installing %1$s…</string>\n    <string name=\"add_app_loading_complete\">%1$s successfully installed. </string>\n    <string name=\"list_app_activity_install\">Add to VirtualXposed</string>\n    <string name=\"settings_about_text\">About</string>\n    <string name=\"settings_task_manage_text\">Manage Tasks</string>\n    <string name=\"settings_app_manage_text\">Manage Apps</string>\n    <string name=\"settings_desktop_text\">Desktop Settings</string>\n    <string name=\"app_manage_uninstall\">Uninstall</string>\n    <string name=\"app_manage_repair\">Repair</string>\n    <string name=\"settings_title\">Settings</string>\n    <string name=\"task_manage_uninstall\">Kill Process</string>\n    <string name=\"settings_reboot_title\">Reboot VirtualXposed</string>\n    <string name=\"settings_reboot_content\">This will kill all apps currently running in VirtualXposed. Reboot anyway?</string>\n    <string name=\"check_update\">Check Update</string>\n    <string name=\"version_is_latest\">Latest version is installed.</string>\n    <string name=\"new_version_detected\">New Version:</string>\n    <string name=\"multi_version_tip_title\">Install tips</string>\n    <string name=\"multi_version_tips_content\">You have chosen an existing app. Do you want to install it as a separate app, or just update the existing one? \\n(Installed version %1$s, Selected version: %2$s)</string>\n    <string name=\"multi_version_multi\">Install another one</string>\n    <string name=\"multi_version_cover\">Cover</string>\n    <string name=\"multi_version_upgrade\">Upgrade</string>\n    <string name=\"multi_version_downgrade\">Downgrade</string>\n    <string name=\"app_manage_repair_failed_tips\" >Sorry, repair failed; please re-install this app.</string>\n    <string name=\"app_manage_repairing\">Repairing…</string>\n    <string name=\"app_manage_repair_success_title\">Repair tips</string>\n    <string name=\"app_manage_repair_success_content\">Repair success; please force-stop VirtualXposed for it to take effect.</string>\n    <string name=\"app_manage_repair_reboot_now\">Reboot now</string>\n    <string name=\"wallpaper_too_big_tips\">The wallpaper choosen is too large and may increase the startup time, please choose a proper one.</string>\n    <string name=\"create_shortcut_already_exist\">This shortcut already exists</string>\n    <string name=\"start_app_failed\">Open app: %1$s failed.</string>\n    <string name=\"app_manage_redirect_on\">Open Storage Redirect</string>\n    <string name=\"app_manage_redirect_off\">Disable Storage Redirect</string>\n    <string name=\"app_manage_redirect_desc\">Storage Redirection redirects an application\\'s access from the real SD card to a virtual SD card, which will prevent certain apps from creating directories in your real SD card; however, after the storage redirection is enabled, the application can no longer access the real SD card. Please select it when prompted.</string>\n    <string name=\"app_manage_redirect_on_confirm\">Open, Confirm</string>\n    <string name=\"app_manage_redirect_off_confirm\">Close, Confirm</string>\n    <string name=\"shared_to_vxp\">Share to App in VirtualXposed</string>\n    <string name=\"shared_to_vxp_failed\">Share failed, please try again.</string>\n    <string name=\"app_installer_label\">Add to VirtualXposed</string>\n    <string name=\"install_complete\">DONE</string>\n    <string name=\"install_fail\">Install failed: %1$s</string>\n    <string name=\"install\">Install</string>\n    <string name=\"install_package\">Install new app: %s</string>\n    <string name=\"install_package_version_tips\">You have chosen an existing app, \\n(Installed version %1$s, selected version: %2$s). Install it?</string>\n    <string name=\"settings_add_app_summary\">Please add both the app and the Xposed module to VirtualXposed first, otherwise the Xposed module won\\'t take effect.</string>\n    <string name=\"settings_advance\">Advanced Settings</string>\n    <string name=\"advance_settings_hide_settings\">Hide settings button on desktop</string>\n    <string name=\"advance_settings_disable_installer\">Disable apk installer for system</string>\n    <string name=\"advance_settings_hide_settings_summary\">If you can enter settings by the menu key on main activity, you can hide this; you may not be able to enter settings otherwise! \\n(Restart VirtualXposed to take effect.)</string>\n    <string name=\"advance_settings_disable_installer_summary\">Do not show VirtualXposed\\'s installer when you choose apk file in system</string>\n    <string name=\"advance_settings_directly_back\">Directly back</string>\n    <string name=\"advance_settings_directly_back_summary\">Go back to the system launcher instead of the virtual launcher when in a virtual app.\\n(Restart VirtualXposed to take effect.)</string>\n    <string name=\"install_self_eggs\">Boy, your idea is promising :)</string>\n    <string name=\"advance_settings_install_gms\">Install/Uninstall Google Services</string>\n    <string name=\"about_feedback_tel_title\">Telegram Group: %1$s</string>\n    <string name=\"advance_settings_copy_file\">Copy File</string>\n    <string name=\"about_website_title\">Official website</string>\n    <string name=\"about_feedback_title\">Feedback</string>\n    <string name=\"about_feedback_hint\">Please specify your phone model, Android version, Xposed plugin, and version of the corresponding app, and then describe (in as much detail as possible) the problem you are experiencing, otherwise it is considered invalid feedback (because we can\\'t effectively troubleshoot and fix said problem with only \\\"this app crashes\\\" ;) )</string>\n    <string name=\"settings_plugin_recommend\">Recommended Xposed Modules</string>\n    <string name=\"advance_settings_disable_resident_notification\">Disable persistent notification</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">Disable the persistent notification of VirtualXposed. (When disabled, VirtualXposed may be killed by the system frequently. Use with caution!)</string>\n    <string name=\"settings_module_manage\">Manage Xposed Module</string>\n    <string name=\"settings_module_manage_summary\">Enable/Disable Xposed module (You must enable it manually for it to take effect)</string>\n    <string name=\"xposed_installer_not_found\">Xposed Installer not found, please add it to VirtualXposed first!</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">When enabled, you can install apk which has no signatures(Usually applies to cracked/modded apps, please be careful\n)</string>\n    <string name=\"advance_settings_allow_fake_signature\">Allow to install apk without signatures.</string>\n    <string name=\"permission_tip_title\">Important tips:</string>\n    <string name=\"permission_tips_content\">%1$s  doesn\\'t support runtime permission, you must give permissions it needs in advance, please allow all the permission it will request in next step, otherwise it may not work properly.</string>\n    <string name=\"permission_tips_confirm\">OK, I know.</string>\n    <string name=\"permission_denied_tips_content\">App: %1$s doesn\\'t grant necessary permission, if it doesn\\'t work properly, please go to your device\\'s permission management and give it permissions.</string>\n    <string name=\"list_app_access_external_storage\">If you want to install apk from external storage, please give VirtualXposed the permission.</string>\n    <string name=\"install_gms_title\" >Install Google Service</string>\n    <string name=\"install_gms_content\">The Google Service is supported by microG, VirtualXposed is about to download some file(2M), and it may consume more battery, would you like to install it?</string>\n    <string name=\"install_gms_fail_title\">Install failed</string>\n    <string name=\"install_gms_fail_content\">Install Google Service automatically failed, you can also install it manually.</string>\n    <string name=\"install_gms_fail_ok\">Manual Install</string>\n    <string name=\"uninstall_gms_title\">Uninstall Google Service</string>\n    <string name=\"uninstall_gms_content\">Would you like to uninstall Google Service? you can reinstall it later.</string>\n    <string name=\"uninstall_gms_ok\">Uninstall, Confirm</string>\n    <string name=\"install_gms_alreay_installed\">The Google Service has been installed.</string>\n    <string name=\"install_gms_success\">Google Service has been installed successfully!!</string>\n    <string name=\"uninstall_gms_success\">Google Service has been uninstalled successfully!!</string>\n    <string name=\"donate_choose_title\">Way to donate</string>\n    <string name=\"donate_bitconins_tips\">My bitconins address has been copied to clipboard:)</string>\n    <string name=\"advance_settings_disable_xposed_summary\">When disabled, all Xposed module won\\'t take effect.</string>\n    <string name=\"advance_settings_disable_xposed\">Disable Xposed</string>\n    <string name=\"prepare_xposed_installer\">Preparing Xposed environment, please wait…</string>\n    <string name=\"settings_file_manage_text\">File Manager</string>\n    <string name=\"install_file_manager_tips\">File Manager is supported by Amaze File Manager, download(about 3M) and install it now?</string>\n    <string name=\"settings_permission_manage_text\">Permission Manager</string>\n    <string name=\"install_permission_manager_tips\">Permission Manager is implemented by XPrivacyLua, download(about 1.7M) and install it now?</string>\n    <string name=\"exp_tips\">A long time ago, I revealed the information about EXposed. After a period of feedback and adjustment, EXposed has reached a milestone. Many users may don\\'t know it, let me introduce you today. \\n\\n\n\nLike the VirtualXposed I created earlier, EXposed is also an app that makes you use Xposed module without root, unlock the bootloader. they both have their own advantages, and EXposed will be much better in terms of performance and stability due to running directly in the native system; while VirtualXposed is based on VitualApp, which is like Parallel Space. EXposed was born a month, and its stability has surpassed VirtualXposed which has been developed for nearly a year. \\n\\n\n\nCurrently, EXposed has been put on the app store and renamed to Tai Chi. You can try it out :)</string>\n    <string name=\"advance_settings_enable_launcher_summary\">When enabled, You can set VirtualXposed be the Launcher of system</string>\n    <string name=\"advance_settings_enable_launcher\">Enable Launcher</string>\n    <string name=\"exp_introduce_title\">An easy way to use Xposed</string>\n    <string name=\"exp_introduce_install\">Have a try</string>\n    <string name=\"what_is_exp\">What\\'s TaiChi?</string>\n    <string name=\"install_choose_way\">Choose way to install</string>\n    <string name=\"install_choose_content\" >You can use Xposed modules through TaiChi except VirtualXposed. VirtualXposed supports Virtual-App，while TaiChi is much more stable.</string>\n    <string name=\"install_choose_taichi\">TaiChi</string>\n    <string name=\"install_taichi_not_exist\">TaiChi is not installed!</string>\n    <string name=\"install_go_to_install_exp\">Go to install TaiChi</string>\n    <string name=\"install_taichi_while_old_version\">The version of TaiChi installed is too old, Please install the latest Taichi!</string>\n    <string name=\"install_go_latest_exp\">Install the latest TaiChi</string>\n    <string name=\"install_complete_and_open\">Open</string>\n    <string name=\"unsupported_for_32bit_app\">32bits App is not supported!</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.NoActionBar\">\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:windowIsTranslucent\">false</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:textAllCaps\">false</item>\n    </style>\n\n    <style name=\"UITheme\" parent=\"Theme.AppCompat.NoActionBar\">\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:textAllCaps\">false</item>\n    </style>\n\n    <style name=\"TransparentTheme\" parent=\"AppTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"colorPrimary\">@android:color/background_dark</item>\n        <item name=\"colorPrimaryDark\">@android:color/background_dark</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowAnimationStyle\">@null</item>\n    </style>\n\n    <style name=\"VAAlertTheme\" parent=\"Theme.AppCompat.Light.Dialog.Alert\" />\n\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.AppCompat.Dark.ActionBar\"/>\n\n    <style name=\"AppTheme.PopupOverlay\" parent=\"ThemeOverlay.AppCompat.Light\"/>\n\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-en/strings.xml",
    "content": "<resources>\n    <!--Avoid to be Override By library-->\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"versionchecklib_confirm\">Upgrade now</string>\n    <string name=\"list_app_access_external_storage\">If you want to install apk from external storage, please give VirtualXposed the permission.</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-es/strings.xml",
    "content": "<resources>\n    <!--<string name=\"app_name\">VirtualApp</string>-->\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"wait\">Espere, por favor…</string>\n    <string name=\"desktop\">Escritorio</string>\n    <string name=\"add_app\">Agregar aplicación</string>\n    <string name=\"preparing\">Abriendo aplicación…</string>\n    <string name=\"delete\">Eliminar</string>\n    <string name=\"create_shortcut\">Crear acceso directo</string>\n    <string name=\"new_user\">Nuevo usuario</string>\n    <string name=\"enable\">Activar</string>\n    <string name=\"save\">Guardar</string>\n    <string name=\"save_success\">¡Se ha guardado con éxito!</string>\n    <string name=\"manufacturer\">Fabricante</string>\n    <string name=\"brand\">Marca</string>\n    <string name=\"device\">Dispositivo</string>\n    <string name=\"fake_device_info\">Información de dispositivo falsa</string>\n    <string name=\"wifi_status\">Estado de Wi-Fi</string>\n    <string name=\"config_device_info\">Información de dispositivo</string>\n    <string name=\"about\">Acerca de…</string>\n    <string name=\"clone_apps\">Clonar aplicaciones</string>\n    <string name=\"external_storage\">Almacenamiento externo</string>\n    <string name=\"install_d\">Instalar (%d)</string>\n    <string name=\"install_too_much_once_time\">¡No se pueden elegir más de 9 aplicaciones al mismo tiempo!</string>\n    <string name=\"versionchecklib_confirm\">Descargar</string>\n    <string name=\"versionchecklib_cancel\">Cancelar</string>\n    <string name=\"menu_virtual_location\">Ubicación virtual</string>\n    <string name=\"menu_about\">Acerca de…</string>\n    <string name=\"menu_reboot\">Reiniciar</string>\n    <string name=\"installing_tips\">Instalando %1$s…</string>\n    <string name=\"update_success_tips\">¡Se actualizó %1$s con éxito!</string>\n    <string name=\"install_success_tips\">El módulo Xposed no entrará en efecto hasta que lo haya activado en la sección Módulos de la aplicación XposedInstaller!</string>\n    <string name=\"install_fail_tips\">La instalación de %1$s falló: %2$s</string>\n    <string name=\"copy_right\" translatable=\"false\">Todos los derechos reservados © %1$d</string>\n    <string name=\"about_page_description\">VirtualXposed es una aplicación que otorga la posibilidad de utilizar un módulo Xposed sin tener root, sin desbloquear el bootloader y sin modificar la imágen del sistema.</string>\n    <string name=\"about_feedback_qq_title\">Grupo QQ</string>\n    <string name=\"about_feedback_wechat_title\">Grupo WeChat</string>\n    <string name=\"about_feedback_tips\">¡El número del grupo ha sido copiado al portapaleles!</string>\n    <string name=\"about_version_title\">Versión: %1$s</string>\n    <string name=\"about_donate_title\">Donar</string>\n    <string name=\"reboot_tips_1\">¡Reinicio completado con éxtio!</string>\n    <string name=\"reboot_tips_2\">¡Reinicio completado con éxtio!</string>\n    <string name=\"reboot_tips_3\">¡Reinicio completado con éxtio!</string>\n    <string name=\"meizu_device_tips_title\">Detectado dispositivo Meizu: </string>\n    <string name=\"meizu_device_tips_content\">En el SO Meizu, solo se puede utilizar la clonación de aplicaciones de VirtualXposed. Por favor instale XposedInstaller primero.</string>\n    <string name=\"donate_alipay\">Alipay</string>\n    <string name=\"donate_wepay\">Wechat Pay</string>\n    <string name=\"prompt_alipay_not_found\">No se encontró Alipay</string>\n    <string name=\"prompt_wait\">Por favor, espero un momento…</string>\n    <string name=\"donate_dialog_title\">Sobre donar…</string>\n    <string name=\"donate_dialog_content\">El mantenimiento de VirtualXposed cuesta mucho de mi tiempo, si aprecias mi trabajo, ¡cómprame una taza de café! :)</string>\n    <string name=\"donate_dialog_yes\">Donar</string>\n    <string name=\"donate_dialog_no\">Cancelar</string>\n    <string name=\"large_app_install_tips\">La instalación puede demorar un tiempo, por favor sé paciente :)</string>\n    <string name=\"about_icon_title\">Acerca de Icon</string>\n    <string name=\"about_icon_content\">Si el nuevo icono no es de tu agrado, por favor, diseña un nuevo icono para VirtualXposed</string>\n    <string name=\"about_icon_yes\">Aceptar</string>\n    <string name=\"create_shortcut_success\">Acceso directo creado con éxito</string>\n    <string name=\"about_thanks\">Gracias</string>\n    <string name=\"thanks_dialog_title\">Gracias</string>\n    <string name=\"thanks_dialog_content\">Gracias Cheney por proporcionar un icono increíble y gracias por el arduo trabajo de Pei, Page y otros diseñadores, que no sé el nombre. Gracias por las ideas y sugerencias que me brindadas por colaboradores. Un agradecimiento especial a YingLin por ayudarme a comprenderme. El diseño pulposo :)</string>\n    <string name=\"alert_for_doze_mode_title\">Consejos</string>\n    <string name=\"alert_for_doze_mode_content\">Por favor, permita que VirtualXposed se ejecute en segundo plano, de lo contrario puede que no reciba notificaciones de alguna aplicación del entorno virtual.</string>\n    <string name=\"alert_for_doze_mode_yes\">Permitir</string>\n    <string name=\"alert_for_doze_mode_no\">Denegar</string>\n    <string name=\"about_faq_title\">Preguntas frecuentes</string>\n    <string name=\"clear_app\">Borrar\\ndatos</string>\n    <string name=\"stop_app\">Forzar\\ndetención</string>\n    <string name=\"home_menu_delete_title\">Eliminar aplicación</string>\n    <string name=\"home_menu_delete_content\">¿Desea eliminar %1$s ?</string>\n    <string name=\"home_menu_clear_title\">Borrar datos</string>\n    <string name=\"home_menu_clear_content\">¿Desea borrar los datos de %1$s ?</string>\n    <string name=\"home_menu_kill_title\">Forzar detención</string>\n    <string name=\"home_menu_kill_content\">¿Desea forzar la detención de %1$s? Hacer esto puede causar que la aplicación no funcione correctamente.</string>\n    <string name=\"add_app_loading_tips\">Analizando paquete de la aplicación %1$s</string>\n    <string name=\"add_app_installing_tips\">Instalando %1$s</string>\n    <string name=\"add_app_loading_complete\">%1$s se instaló con éxito</string>\n    <string name=\"list_app_activity_install\">Agregar a VirtualXposed</string>\n    <string name=\"settings_about_text\">Acerca de…</string>\n    <string name=\"settings_task_manage_text\">Administrador de tareas</string>\n    <string name=\"settings_app_manage_text\">Administrador de aplicaciones</string>\n    <string name=\"settings_desktop_text\">Configuración de escritorio</string>\n    <string name=\"app_manage_uninstall\">Desinstalar</string>\n    <string name=\"app_manage_repair\">Reparar</string>\n    <string name=\"settings_title\">Configuración</string>\n    <string name=\"task_manage_uninstall\">Matar proceso</string>\n    <string name=\"settings_reboot_title\">Reiniciar VirtualXposed</string>\n    <string name=\"settings_reboot_content\">Esta opción detendrá forzosamente todas las aplicaciones en ejecucuón en VirtualXposed. ¿Desea continuar?</string>\n    <string name=\"check_update\">Comprobar si hay actualizaciones</string>\n    <string name=\"version_is_latest\">Última versión instalada:</string>\n    <string name=\"new_version_detected\">Nueva versión:</string>\n    <string name=\"multi_version_tip_title\">Consejos de instalación</string>\n    <string name=\"multi_version_tips_content\">Ha seleccionado una aplicación existente. ¿Desea clonar una nueva aplicación y actualizar la existente? \\n(Versión instalada %1$s, versión seleccionada: %2$s)</string>\n    <string name=\"multi_version_multi\">Clonar nueva</string>\n    <string name=\"multi_version_cover\">Cubrir</string>\n    <string name=\"multi_version_upgrade\">Actualizar</string>\n    <string name=\"multi_version_downgrade\">Degradar</string>\n    <string name=\"app_manage_repair_failed_tips\">Lo siento, la reparación a fallado, por favor, reinstala esta aplicación</string>\n    <string name=\"app_manage_repairing\">Reparando</string>\n    <string name=\"app_manage_repair_success_title\">Consejos de reparación</string>\n    <string name=\"app_manage_repair_success_content\">La reparación se realizó con éxito, por favor, detenga forzozamente VirtualXposed para que los cambios surtan efecto.</string>\n    <string name=\"app_manage_repair_reboot_now\">Reiniciar ahora</string>\n    <string name=\"wallpaper_too_big_tips\">La imágen de fondo es muy grande y hará mas lento el inicio del entorno, por favor, seleccione otra imágen de un tamaño adecuado.</string>\n    <string name=\"create_shortcut_already_exist\">El acceso directo ya existe</string>\n    <string name=\"start_app_failed\">Abrir aplicación: %1$s falló.</string>\n    <string name=\"app_manage_redirect_on\">Redirección de abrir almacenamiento</string>\n    <string name=\"app_manage_redirect_off\">Desactivar redirección de almacenamiento</string>\n    <string name=\"app_manage_redirect_desc\" />\n    <string name=\"app_manage_redirect_on_confirm\">Abrir, confirmar</string>\n    <string name=\"app_manage_redirect_off_confirm\">Cerrar, confirmar</string>\n    <string name=\"shared_to_vxp\">Compartir en aplicación de VirtualXposed</string>\n    <string name=\"shared_to_vxp_failed\">Compartir falló, por favor intentar nuevamente.</string>\n    <string name=\"app_installer_label\">Agregar a VirtualXposed</string>\n    <string name=\"install_complete\">Instalación terminada</string>\n    <string name=\"install_fail\">Fallo en la instalación: : %1$s</string>\n    <string name=\"install\">Instalar</string>\n    <string name=\"install_package\">Instalar nueva aplicación: %s</string>\n    <string name=\"install_package_version_tips\">Ha seleccionado una aplicación existente, ¿desea instalarla? \\n(Versión instalada %1$s, versión seleccionada: %2$s)</string>\n    <string name=\"settings_add_app_summary\">Por favor, agregue tanto la aplicación como el módulo Xposed a VirtualXposed primero, de lo contario el módulo Xposed no surtirá efecto.</string>\n    <string name=\"settings_advance\">Configuración avanzada</string>\n    <string name=\"advance_settings_hide_settings\">Ocultar ícono de configuración en escritorio</string>\n    <string name=\"advance_settings_disable_installer\">Desactivar instalación de aplicaciones para el sistema</string>\n    <string name=\"advance_settings_hide_settings_summary\">Si puede ingresar a la configuración a través de un botón menú en la actividad principal, puede ocultarlo, de lo contrario puede que no tenga la posibilidad de ingresar a la configuración.\\n(Reiniciar VirtualXposed para que los cambios surtan efecto)</string>\n    <string name=\"advance_settings_disable_installer_summary\">No mostrar el instalador de VirtualXposed cuando se selecciona un archivo apk en el sistema</string>\n    <string name=\"advance_settings_directly_back\">Retorno directo</string>\n    <string name=\"advance_settings_directly_back_summary\">Retornar al lanzador del sistema en vez del lanzador vitual cuando se está en una aplicación virtualizada.\\n(Reiniciar VirtualXposed para que los cambios surtan efecto)</string>\n    <string name=\"install_self_eggs\">Chico, tu idea es prometedora :)</string>\n    <string name=\"about_feedback_tel_title\">Grupo de Telegram: %1$s</string>\n    <string name=\"advance_settings_install_gms\">Instalar / Desinstalar servicios de Google</string>\n    <string name=\"advance_settings_copy_file\">Copiar archivo</string>\n    <string name=\"about_website_title\">Sitio web oficial</string>\n    <string name=\"about_feedback_title\">Comentarios</string>\n    <string name=\"about_feedback_hint\">Especifique el modelo, la versión del sistema, el complemento Xposed utilizado y la versión de la aplicación correspondiente, y luego describa con el mayor detalle posible el problema que está experimentando, de lo contrario, se considera como un comentario no válido.\\n</string>\n    <string name=\"settings_plugin_recommend\">Módulo Xposed recomendado</string>\n    <string name=\"advance_settings_disable_resident_notification\">Desactivar las notificaciones de residentes</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">Después de cerrar la barra de notificaciones residentes, VirtualXposed podría ser eliminado fácilmente por el sistema, lo que provocaría problemas como la imposibilidad de recibir mensajes, y si puede asegurarse de que VirtualXposed no muera, puede intentarlo. En resumen, operación cuidadosa! (Efectivo después de reiniciar VirtualXposed)</string>\n    <string name=\"settings_module_manage\">Gestión de módulos</string>\n    <string name=\"settings_module_manage_summary\">Encienda o apague el módulo Xposed (el módulo Xposed debe encenderse manualmente después de la instalación para que tenga efecto)</string>\n    <string name=\"xposed_installer_not_found\">Instalador Xposed no encontrado, por favor agrégalo a VirtualXposed!</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">Cuando está habilitado, puede instalar apk que no tiene firmas (Generalmente se usa en apk craqueado, Por favor, preste atención a la seguridad)</string>\n    <string name=\"advance_settings_allow_fake_signature\">Permitir la instalación de apk sin firmas.</string>\n    <string name=\"permission_tip_title\">Important Tips:</string>\n    <string name=\"permission_tips_content\">%1$s no admite permisos de tiempo de ejecución, debe otorgar los permisos que necesita de antemano, permita todos los permisos que solicitará en el siguiente paso, de lo contrario, puede que no funcione correctamente.</string>\n    <string name=\"permission_tips_confirm\">Yo se</string>\n    <string name=\"permission_denied_tips_content\">Aplicación: %1$s no otorga el permiso necesario, si no funciona correctamente, vaya a la administración de permisos de su dispositivo y otórguele permisos.</string>\n    <string name=\"list_app_access_external_storage\">Si desea instalar apk desde el almacenamiento externo, dele el permiso a VirtualXposed.</string>\n    <string name=\"install_gms_title\"></string>\n    <string name=\"install_gms_content\">El servicio de Google es compatible con microG, VirtualXposed está a punto de descargar un archivo (2M) y puede consumir más batería, ¿le gustaría instalarlo?</string>\n    <string name=\"install_gms_fail_title\">Instalación fallida</string>\n    <string name=\"install_gms_fail_content\">Instalar Google Service falló automáticamente, también puede instalarlo manualmente.</string>\n    <string name=\"install_gms_fail_ok\">Manual de instalación</string>\n    <string name=\"uninstall_gms_title\">Desinstalar el servicio de Google</string>\n    <string name=\"uninstall_gms_content\">¿Desea desinstalar el servicio de Google? puedes reinstalarlo más tarde.</string>\n    <string name=\"uninstall_gms_ok\">Desinstalar, confirmar</string>\n    <string name=\"install_gms_alreay_installed\">El servicio de Google ha sido instalado.</string>\n    <string name=\"install_gms_success\">¡El servicio de Google se ha instalado con éxito!</string>\n    <string name=\"uninstall_gms_success\">El servicio de Google ha sido desinstalado con éxito.</string>\n    <string name=\"donate_choose_title\">Forma de donar</string>\n    <string name=\"donate_bitconins_tips\">Mi dirección de bitconins ha sido copiada al portapapeles :)</string>\n    <string name=\"advance_settings_disable_xposed_summary\">Cuando está deshabilitado, todo el módulo Xposed no tendrá efecto.</string>\n    <string name=\"advance_settings_disable_xposed\">Deshabilitar Xposed</string>\n    <string name=\"prepare_xposed_installer\">Preparación del entorno Xposed, espere ...</string>\n    <string name=\"settings_file_manage_text\">File Manage</string>\n    <string name=\"install_file_manager_tips\">File Manager es compatible con Amaze File Manager, descarga (aproximadamente 3M) e instálalo ahora.</string>\n    <string name=\"settings_permission_manage_text\">Permiso Administrar</string>\n    <string name=\"install_permission_manager_tips\">Permission Manage es implementado por XPrivacyLua, descarga (aproximadamente 1.7M) e instálalo ahora?</string>\n    <string name=\"advance_settings_enable_launcher_summary\">Enable Launcher</string>\n    <string name=\"advance_settings_enable_launcher\">Enable Launcher</string>\n    <string name=\"install_complete_and_open\">Abierto</string>\n    <string name=\"unsupported_for_32bit_app\">¡Las aplicaciones de 32 bits no son compatibles!</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-fr/strings.xml",
    "content": "<resources>\n    <string name=\"wait\">Veuillez patienter…</string>\n    <string name=\"desktop\">Bureau</string>\n    <string name=\"add_app\">Ajouter une app</string>\n    <string name=\"preparing\">Ouvrir appli…</string>\n    <string name=\"delete\">Supprimer</string>\n    <string name=\"create_shortcut\">Créer un raccourci</string>\n    <string name=\"new_user\">Nouvel utilisateur</string>\n    <string name=\"enable\">Activer</string>\n    <string name=\"save\">Sauvegarder</string>\n    <string name=\"save_success\">Sauvegarde accomplie!</string>\n    <string name=\"manufacturer\">Fabricant</string>\n    <string name=\"brand\">Marque</string>\n    <string name=\"device\">Périphérique</string>\n    <string name=\"fake_device_info\">Infos périphérique trompeur</string>\n    <string name=\"wifi_status\">Status WIFI</string>\n    <string name=\"config_device_info\">Infos périphérique</string>\n    <string name=\"about\">A propos</string>\n    <string name=\"clone_apps\">Cloner Applis</string>\n    <string name=\"external_storage\">Stockage externe</string>\n    <string name=\"install_d\">Installation (%d)</string>\n    <string name=\"install_too_much_once_time\">Pas plus de 9 applis ne peuvent être choisis en même temps!</string>\n    <string name=\"versionchecklib_confirm\">Téléchargement</string>\n    <string name=\"versionchecklib_cancel\">Annuler</string>\n    <string name=\"menu_virtual_location\">Localisation trompeuse</string>\n    <string name=\"menu_about\">A propos</string>\n    <string name=\"menu_reboot\">Redémarrage</string>\n    <string name=\"installing_tips\">Installation %1$s…</string>\n    <string name=\"update_success_tips\">Mise à jour de %1$s réussie!</string>\n    <string name=\"install_success_tips\">Le module Xposed ne prendra pas effet tant que vous ne l\\'aurez pas activé dans les réglages de l\\'installateur Xposed.</string>\n    <string name=\"install_fail_tips\">L\\'installation de %1$s échouée: %2$s</string>\n    <string name=\"copy_right\" translatable=\"false\" >Droits d\\'utilisations © %1$d</string>\n    <string name=\"about_page_description\">VirtualXposed est une appli qui fournie la possibilité d\\'utiliser le module Xposed sans avoir besoin d\\'accès root, débloquer l\\'image de démarrage, ou modifier l\\'image système.</string>\n    <string name=\"about_feedback_qq_title\">Groupe QQ Group (Toucher pour copier le numéro de groupe)</string>\n    <string name=\"about_feedback_wechat_title\">Groupe WeChat (Toucher pour copier)</string>\n    <string name=\"about_feedback_tips\">Le numéro du groupe a été copié dans le presse-papier!</string>\n    <string name=\"about_version_title\">Version: %1$s</string>\n    <string name=\"about_donate_title\">Don</string>\n    <string name=\"reboot_tips_1\">Redémarrage réussi!</string>\n    <string name=\"reboot_tips_2\">Redémarrage réussi!</string>\n    <string name=\"reboot_tips_3\">Redémarrage réussi!</string>\n    <string name=\"meizu_device_tips_title\">Détecter périphérique Meizu: </string>\n    <string name=\"donate_alipay\">Alipay</string>\n    <string name=\"donate_wepay\">Paiement Wechat</string>\n    <string name=\"prompt_alipay_not_found\">Alipay non trouvé.</string>\n    <string name=\"prompt_wait\">Patienter juste un moment…</string>\n    <string name=\"donate_dialog_title\">A propos des dons</string>\n    <string name=\"donate_dialog_content\">La maintenance de VirtualXposed prend beaucoup de temps, si vous appréciez mon travail, achetez-moi une tasse de café! :)</string>\n    <string name=\"donate_dialog_yes\">Don</string>\n    <string name=\"donate_dialog_no\">Annuler</string>\n    <string name=\"large_app_install_tips\">L\\'installation peut prendre un certain temps, merci d\\'être patient… :)</string>\n    <string name=\"about_icon_title\">A propos de l\\'icône</string>\n    <string name=\"about_icon_content\">Si vous n\\'aimez pas la nouvelle icône, vous êtes toujours le bienvenu pour produire une nouvelle icône pour VirtualXposed ;)</string>\n    <string name=\"about_icon_yes\">OK</string>\n    <string name=\"create_shortcut_success\">La création du raccourcis a été réussie!</string>\n    <string name=\"about_thanks\">Remerciements</string>\n    <string name=\"thanks_dialog_title\">Merci</string>\n    <string name=\"thanks_dialog_content\">Merci à Cheney d\\'avoir fournis une icône magnifique, et merci à vous Pei, Peggy, et beaucoup d\\'autres de la liste, pour votre grand travail. Merci pour vos idées et suggestions que vous avez fourni, et un remerciement tout à fait spécial à YingLin pour avoir pris le temps de m\\'aider à achever mon interface :)</string>\n    <string name=\"alert_for_doze_mode_title\">Indices</string>\n    <string name=\"alert_for_doze_mode_content\">Merci de permettre à VirtualXposed de fonctionner en fond de tâche, vous ne pourriez cependant ne pas recevoir de notifications de certaines applis virtuelles.</string>\n    <string name=\"alert_for_doze_mode_yes\">Permettre</string>\n    <string name=\"alert_for_doze_mode_no\">Refuser</string>\n    <string name=\"about_faq_title\">FAQ</string>\n    <string name=\"clear_app\">Clear\\nDonnées</string>\n    <string name=\"stop_app\">Forcer\\nStopper</string>\n    <string name=\"home_menu_delete_title\">Supprimer l\\'application</string>\n    <string name=\"home_menu_delete_content\">Voulez-vous supprimer %1$s ?</string>\n    <string name=\"home_menu_clear_title\">Effacer les données</string>\n    <string name=\"home_menu_clear_content\">Voulez-vous supprimer les données de %1$s ?</string>\n    <string name=\"home_menu_kill_title\">Forcer l\\'arrêt</string>\n    <string name=\"home_menu_kill_content\">Voulez-vous forcer l\\'arrêt de %1$s ? Cela peut entraîner un fonctionnement inattendu.</string>\n    <string name=\"add_app_loading_tips\">Analyse du paquet %1$s…</string>\n    <string name=\"add_app_installing_tips\">Installation de %1$s…</string>\n    <string name=\"add_app_loading_complete\">%1$s installé avec succès.</string>\n    <string name=\"list_app_activity_install\">Ajouter à VirtualXposed</string>\n    <string name=\"settings_about_text\">A propos de</string>\n    <string name=\"settings_task_manage_text\">Gestionnaire de tâches</string>\n    <string name=\"settings_app_manage_text\">Gérer les applications</string>\n    <string name=\"settings_desktop_text\">Réglages Bureau</string>\n    <string name=\"app_manage_uninstall\">Désinstaller</string>\n    <string name=\"app_manage_repair\">Réparer</string>\n    <string name=\"settings_title\">Réglages</string>\n    <string name=\"task_manage_uninstall\">Tuer Processus</string>\n    <string name=\"settings_reboot_title\">Redémarrer VirtualXposed</string>\n    <string name=\"settings_reboot_content\">Ceci tuera toutes les applications qui s\\'exécutent actuellement dans VirtualXposed. Redémarrer quand même?</string>\n    <string name=\"check_update\">Vérifier mises à jours</string>\n    <string name=\"version_is_latest\">La dernière version est installée.</string>\n    <string name=\"new_version_detected\">Nouvelle version:</string>\n    <string name=\"multi_version_tip_title\">Conseils d\\'installation</string>\n    <string name=\"multi_version_tips_content\">Vous avez choisi une application existante. Voulez-vous l\\'installer en tant qu\\'application séparée ou simplement mettre à jour l\\'application existante ? \\n(Version installée %1$s, Version sélectionnée : %2$s)</string>\n    <string name=\"multi_version_multi\">En installer une autre</string>\n    <string name=\"multi_version_cover\">Par-dessus</string>\n    <string name=\"multi_version_upgrade\">Mise à jour</string>\n    <string name=\"multi_version_downgrade\">Downgrade</string>\n    <string name=\"app_manage_repair_failed_tips\">Désolé, réparation échouée; veuillez installer à nouveau l\\'appli.</string>\n    <string name=\"app_manage_repairing\">Réparation…</string>\n    <string name=\"app_manage_repair_success_title\">Conseils de réparation</string>\n    <string name=\"app_manage_repair_success_content\">Réparation effectuée avec succès; merci de forcer l\\'arrêt de VirtualXposed pour que le changement soit pris en compte.</string>\n    <string name=\"app_manage_repair_reboot_now\">Redémarrer maintenant</string>\n    <string name=\"wallpaper_too_big_tips\">L\\'image du fond d\\'écran est trop grande et ralentira le temps de démarrage, veuillez choisir une image correcte.</string>\n    <string name=\"create_shortcut_already_exist\">Ce raccourcis existe déjà</string>\n    <string name=\"start_app_failed\">Ouvrir appli: %1$s échoué.</string>\n    <string name=\"app_manage_redirect_on\">Réacheminement de stockage ouvert</string>\n    <string name=\"app_manage_redirect_off\">Désactiver le réacheminement du stockage</string>\n    <string name=\"app_manage_redirect_desc\">La redirection de stockage redirige l\\'accès d\\'une application de la vraie carte SD vers une carte SD virtuelle, ce qui empêchera certaines applications de créer des répertoires dans votre vraie carte SD ; cependant, une fois la redirection de stockage activée, l\\'application ne peut plus accéder à la vraie carte SD. Veuillez le sélectionner lorsque vous y êtes invité.</string>\n    <string name=\"app_manage_redirect_on_confirm\">Ouvrir, Confirmer</string>\n    <string name=\"app_manage_redirect_off_confirm\">Fermer, Confirmer</string>\n    <string name=\"shared_to_vxp\">Partager à l\\'appli dans VirtualXposed</string>\n    <string name=\"shared_to_vxp_failed\">Échec du partage, merci de réessayer à nouveau.</string>\n    <string name=\"app_installer_label\">Ajouter à VirtualXposed</string>\n    <string name=\"install_complete\">Installation complète.</string>\n    <string name=\"install_fail\">Installation échouée: %1$s</string>\n    <string name=\"install\">Installation</string>\n    <string name=\"install_package\">Installation nouvelle appli: %s</string>\n    <string name=\"install_package_version_tips\">Vous avez choisi une application existante, \\n(Version installée %1$s, version sélectionnée : %2$s). L\\'installer ?</string>\n    <string name=\"settings_add_app_summary\">Veuillez d\\'abord ajouter l\\'application et le module Xposed à VirtualXposed, sinon le module Xposed ne prendra pas effet.</string>\n    <string name=\"settings_advance\">Réglages avancés</string>\n    <string name=\"advance_settings_hide_settings\">Masquer le bouton réglages sur le bureau</string>\n    <string name=\"advance_settings_disable_installer\">Désactiver l\\'installateur apk pour le système</string>\n    <string name=\"advance_settings_hide_settings_summary\">Si vous pouvez saisir les paramètres à l\\'aide de la touche de menu de l\\'activité principale, vous pouvez les masquer ; sinon, vous ne pourrez peut-être pas saisir les paramètres ! \\n(Redémarrer VirtualXposed pour prendre en compte le changement)..)</string>\n    <string name=\"advance_settings_disable_installer_summary\">Ne pas afficher l\\'installateur de VirtualXposed lorsque vous choisissez le fichier apk dans le système.</string>\n    <string name=\"advance_settings_directly_back\">Directement en arrière</string>\n    <string name=\"advance_settings_directly_back_summary\">Revenir au lanceur système au lieu du lanceur virtuel dans une application virtuelle.\\n(Redémarrer VirtualXposed pour prendre en compte le changement.)</string>\n    <string name=\"install_self_eggs\">Mec, Ton idée est prometteuse. :)</string>\n    <string name=\"advance_settings_install_gms\">Installer / Désinstaller les services Google</string>\n    <string name=\"about_feedback_tel_title\">Group Telegram: %1$s</string>\n    <string name=\"advance_settings_copy_file\">Copier fichier</string>\n    <string name=\"about_website_title\">Site web officiel</string>\n    <string name=\"about_feedback_title\">Retour utilisateurs</string>\n    <string name=\"about_feedback_hint\">Veuillez spécifier le modèle de votre téléphone, la version Android, le plugin Xposed et la version de l\\'application correspondante, puis décrivez (avec le plus de détails possible) le problème que vous rencontrez, sinon il est considéré comme un feedback invalide (parce que nous ne pouvons pas résoudre efficacement le problème avec seulement \\\"cette application plante\\\"). ;) )</string>\n    <string name=\"settings_plugin_recommend\">Modules Xposed recommandés</string>\n    <string name=\"advance_settings_disable_resident_notification\">Désactiver la notification de résident</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">Désactive la notification de résident de VirtualXposed. (Lorsque désactivé, VirtualXposed peut être fréquemment tué par le système. Soyez prudents !)</string>\n    <string name=\"settings_module_manage\">Gérer le module Xposed</string>\n    <string name=\"settings_module_manage_summary\">Activer/Désactiver le module Xposed (Vous devez l\\'activer manuellement pour qu\\'il prenne effet.)</string>\n    <string name=\"xposed_installer_not_found\">Xposed Installer n\\'a pas été trouvé, veuillez d\\'abord l\\'ajouter à VirtualXposed !</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">Lorsqu\\'activé, vous pouvez installer apk qui n\\'a pas de signatures (Habituellement utilisé dans les cracks d\\'apks, veuillez faire attention)</string>\n    <string name=\"advance_settings_allow_fake_signature\">Permettre l\\'installation d\\'apk sans signatures.</string>\n    <string name=\"permission_tip_title\">Conseil important :</string>\n    <string name=\"permission_tips_content\">%1$s ne supporte pas l\\'autorisation d\\'exécution, vous devez donner les autorisations dont il a besoin à l\\'avance, veuillez autoriser toutes les permissions qu\\'il demandera à l\\'étape suivante, sinon cela pourrait ne pas fonctionner correctement.</string>\n    <string name=\"permission_tips_confirm\">Ok</string>\n    <string name=\"permission_denied_tips_content\">App: %1$ s n\\'accorde pas l\\'autorisation nécessaire, si cela ne fonctionne pas correctement, veuillez aller à la gestion des permissions de votre appareil et lui donner des permissions.</string>\n    <string name=\"list_app_access_external_storage\">Si vous voulez installer apk à partir d\\'un espace de stockage externe, veuillez donner à VirtualXposed la permission.</string>\n    <string name=\"install_gms_title\" />\n    <string name=\"install_gms_content\">Le service Google est pris en charge par microG, VirtualXposed est sur le point de télécharger un fichier (2M), et il peut consommer plus de batterie, souhaitez-vous l\\'installer ?</string>\n    <string name=\"install_gms_fail_title\">Installation échouée</string>\n    <string name=\"install_gms_fail_content\">L\\'installation de Google Service a échoué automatiquement, vous pouvez également l\\'installer manuellement.</string>\n    <string name=\"install_gms_fail_ok\">Installation manuelle</string>\n    <string name=\"uninstall_gms_title\">Désinstaller le service Google</string>\n    <string name=\"uninstall_gms_content\">Voulez-vous désinstaller Google Service ? Vous pouvez le réinstaller plus tard.</string>\n    <string name=\"uninstall_gms_ok\">Ok</string>\n    <string name=\"install_gms_alreay_installed\">Le service Google a été installé.</string>\n    <string name=\"install_gms_success\">Le service Google a été installé avec succès !!</string>\n    <string name=\"uninstall_gms_success\">Le service Google a été désinstallé avec succès !!</string>\n    <string name=\"donate_choose_title\">Façon de faire un don</string>\n    <string name=\"donate_bitconins_tips\">Mon adresse bitconins a été copiée dans le presse-papiers :)</string>\n    <string name=\"advance_settings_disable_xposed_summary\">Lorsque désactivé, tous les modules Xposed ne prendront effet.</string>\n    <string name=\"advance_settings_disable_xposed\">Désactiver Xposed</string>\n    <string name=\"prepare_xposed_installer\">Préparation de l\\'environnement Xposed, veuillez patienter…</string>\n    <string name=\"settings_file_manage_text\">Gestionnaire de fichiers</string>\n    <string name=\"install_file_manager_tips\">Gestionnaire de fichiers est pris en charge par Amaze File Manager, télécharger (environ 3M) et l\\'installer maintenant ?</string>\n    <string name=\"settings_permission_manage_text\">Gérer les permissions</string>\n    <string name=\"install_permission_manager_tips\">La gestion des permissions est mis en œuvre par XPrivacyLua, télécharger (environ 1,7M) et l\\'installer maintenant ?</string>\n    <string name=\"advance_settings_enable_launcher_summary\">Lorsqu\\'activé, vous pouvez définir VirtualXposed comme launcher du système.</string>\n    <string name=\"advance_settings_enable_launcher\">Activer le launcher</string>\n    <string name=\"exp_introduce_title\">Un moyen facile d\\'utiliser Xposed</string>\n    <string name=\"exp_introduce_install\">Installer</string>\n    <string name=\"what_is_exp\">Aide TaiChi ?</string>\n    <string name=\"install_choose_way\">Méthode d\\'installation</string>\n    <string name=\"install_choose_content\">Vous pouvez utiliser les modules Xposed via TaiChi, à l\\'exception de VirtualXposed. VirtualXposed prend en charge Virtual-App tandis que TaiChi est beaucoup plus stable.</string>\n    <string name=\"install_taichi_not_exist\">TaiChi n\\'est pas installé !</string>\n    <string name=\"install_go_to_install_exp\">Installer TaiChi</string>\n    <string name=\"install_taichi_while_old_version\">La version de TaiChi installée est trop ancienne, veuillez installer la dernière version de Taichi.</string>\n    <string name=\"install_go_latest_exp\">Installer le dernier TaiChi</string>\n    <string name=\"install_complete_and_open\">Ouvrir</string>\n    <string name=\"unsupported_for_32bit_app\">Les applications 32 bits ne sont pas prises en charge!</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-ja/strings.xml",
    "content": "\n<resources>\n    <!--<string name=\"app_name\">VirtualApp</string>-->\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"vxp\">VirtualXposed</string>\n    <string name=\"wait\">お待ちください…</string>\n    <string name=\"desktop\">デスクトップ</string>\n    <string name=\"add_app\">アプリを追加</string>\n    <string name=\"preparing\">アプリを開いています…</string>\n    <string name=\"delete\">削除</string>\n    <string name=\"create_shortcut\">ショートカットを作成</string>\n    <string name=\"new_user\">新しいユーザー</string>\n    <string name=\"enable\">有効</string>\n    <string name=\"save\">保存</string>\n    <string name=\"save_success\">セーブ完了</string>\n    <string name=\"manufacturer\">メーカー</string>\n    <string name=\"brand\">ブランド</string>\n    <string name=\"device\">端末</string>\n    <string name=\"fake_device_info\">偽の端末情報</string>\n    <string name=\"wifi_status\">Wifiの状態</string>\n    <string name=\"config_device_info\">端末情報</string>\n    <string name=\"about\">このアプリについて</string>\n    <string name=\"clone_apps\">アプリをクローン</string>\n    <string name=\"external_storage\">内部ストレージ</string>\n    <string name=\"install_d\">インストール (%d)</string>\n    <string name=\"install_too_much_once_time\">一度に選択できるアプリは9個までです。</string>\n    <string name=\"versionchecklib_confirm\">ダウンロート</string>\n    <string name=\"versionchecklib_cancel\">キャンセル</string>\n    <string name=\"menu_virtual_location\">仮想ロケーション</string>\n    <string name=\"menu_about\">このアプリについて</string>\n    <string name=\"menu_reboot\">再起動</string>\n    <string name=\"installing_tips\">%1$s をインストール中…</string>\n    <string name=\"update_success_tips\">%1$s をアップデートしました。</string>\n    <string name=\"install_success_tips\">Xposedモジュールは、XposedInstallerのモジュール設定で有効にするまで有効になりません。</string>\n    <string name=\"install_fail_tips\">%1$s のインストールに失敗： %2$s</string>\n    <string name=\"copy_right\" translatable=\"false\" >コピーライト(Copyright) © %1$d</string>\n    <string name=\"about_page_description\">VirtualXposedは、rootアクセスを必要とせず、ブートローダのロックを解除し、システムイメージを変更することなくXposedモジュールを使用する機能を提供するアプリです。</string>\n    <string name=\"about_feedback_qq_title\">QQ グループ（クリックしてグループ番号をコピーする）</string>\n    <string name=\"about_feedback_wechat_title\">WeChat グループ (クリックしてコピー)</string>\n    <string name=\"about_feedback_tips\">グループ番号がクリップボードにコピーされました。</string>\n    <string name=\"about_version_title\">バージョン： %1$s</string>\n    <string name=\"about_donate_title\">寄付する</string>\n    <string name=\"reboot_tips_1\">正常に再起動しました。</string>\n    <string name=\"reboot_tips_2\">正常に再起動しました。</string>\n    <string name=\"reboot_tips_3\">正常に再起動しました。</string>\n    <string name=\"meizu_device_tips_title\">Meizuデバイスを検出: </string>\n    <string name=\"meizu_device_tips_content\">Meizu OSの携帯電話では、すでにインストールされている既存のアプリを複製することによってのみVirtualXposedにアプリを追加できます（apkのサイドロードを介してVirtualXposedにアプリをインストールすることはできません）。 他のAndroid携帯電話へのインストールとは異なり、Meizu OSへのインストール時にVirtualXposedに組み込まれていないため、XposedInstallerも手動でインストールする必要があります。 最初にXposedInstallerをインストールしてください。</string>\n    <string name=\"donate_alipay\">アリペイ</string>\n    <string name=\"donate_wepay\">Wechat Pay</string>\n    <string name=\"prompt_alipay_not_found\">アリペイが見つかりません。</string>\n    <string name=\"prompt_wait\">少しお待ちください...</string>\n    <string name=\"donate_dialog_title\">寄付について</string>\n    <string name=\"donate_dialog_content\">VirtualXposedの維持には私の時間がかかります。あなたが私の仕事に感謝しているなら、私に一杯のコーヒーを買ってください！</string>\n    <string name=\"donate_dialog_yes\">寄付する</string>\n    <string name=\"donate_dialog_no\">キャンセル</string>\n    <string name=\"large_app_install_tips\">インストールにはしばらく時間がかかりますが、しばらくお待ちください…</string>\n    <string name=\"about_icon_title\">アイコンについて</string>\n    <string name=\"about_icon_content\">私の新しいアイコンが気に入らない場合は、VirtualXposedの新しいアイコンをデザインしてください。</string>\n    <string name=\"about_icon_yes\">はい</string>\n    <string name=\"create_shortcut_success\">ショートカットが作成されました。</string>\n    <string name=\"about_thanks\">クレジット</string>\n    <string name=\"thanks_dialog_title\">クレジット</string>\n    <string name=\"thanks_dialog_content\" >素晴らしいアイコンを提供してくれたCheneyに感謝し、そしてあなたの努力のためにPei、Peggy、そしてリストに載せられないほど多くの人たちに感謝します。 皆さんからいただいたアイデアや提案に感謝します。私のデザインを実現するための時間を割いてくれたYingLinに感謝します。</string>\n    <string name=\"alert_for_doze_mode_title\">ヒント</string>\n    <string name=\"alert_for_doze_mode_content\">VirtualXposedをバックグラウンドで実行することを許可してください。そうしないと、一部の仮想アプリケーションから通知を受け取れない場合があります。</string>\n    <string name=\"alert_for_doze_mode_yes\">許可</string>\n    <string name=\"alert_for_doze_mode_no\">拒否</string>\n    <string name=\"about_faq_title\">FAQ</string>\n    <string name=\"clear_app\">データ消去</string>\n    <string name=\"stop_app\">強制停止</string>\n    <string name=\"home_menu_delete_title\">アンインストール</string>\n    <string name=\"home_menu_delete_content\">%1$s をアンインストールしますか？</string>\n    <string name=\"home_menu_clear_title\" >アプリデータ消去</string>\n    <string name=\"home_menu_clear_content\" >%1$s のデータを消去しますか？</string>\n    <string name=\"home_menu_kill_title\">強制停止</string>\n    <string name=\"home_menu_kill_content\">%1$s を強制停止しますか？ これは予期しないアプリの動作を引き起こす可能性があります。 </string>\n    <string name=\"add_app_loading_tips\">%1$s のパッケージを解析中…</string>\n    <string name=\"add_app_installing_tips\">%1$s をインストール中…</string>\n    <string name=\"add_app_loading_complete\">%1$s のインストールが完了しました </string>\n    <string name=\"list_app_activity_install\">VirtualXposedに追加</string>\n    <string name=\"settings_about_text\">このアプリについて</string>\n    <string name=\"settings_task_manage_text\">タスクを管理</string>\n    <string name=\"settings_app_manage_text\">アプリを管理</string>\n    <string name=\"settings_desktop_text\">デスクトップの設定</string>\n    <string name=\"app_manage_uninstall\">アンインストール</string>\n    <string name=\"app_manage_repair\">修復</string>\n    <string name=\"settings_title\">設定</string>\n    <string name=\"task_manage_uninstall\">プロセスをkill</string>\n    <string name=\"settings_reboot_title\">VirtualXposedを再起動</string>\n    <string name=\"settings_reboot_content\">これにより、現在VirtualXposedで実行されているすべてのアプリが強制終了されます。 再起動しますか？</string>\n    <string name=\"check_update\">アップデートをチェック</string>\n    <string name=\"version_is_latest\">最新バージョンがインストールされています。</string>\n    <string name=\"new_version_detected\">最新バージョン:</string>\n    <string name=\"multi_version_tip_title\">インストールのヒント</string>\n    <string name=\"multi_version_tips_content\">既存のアプリを選択しました。 別のアプリとしてインストールしますか、それとも既存のものを更新しますか？ \\n(インストール済みバージョン %1$s, 選択したバージョン: %2$s)</string>\n    <string name=\"multi_version_multi\">別のものをインストール</string>\n    <string name=\"multi_version_cover\">カバー</string>\n    <string name=\"multi_version_upgrade\">更新</string>\n    <string name=\"multi_version_downgrade\">ダウングレード</string>\n    <string name=\"app_manage_repair_failed_tips\" >すみません、修復は失敗しました。 このアプリを再インストールしてください。</string>\n    <string name=\"app_manage_repairing\">修復中...</string>\n    <string name=\"app_manage_repair_success_title\">修復のヒント</string>\n    <string name=\"app_manage_repair_success_content\">修復しました。 それを有効にするためにVirtualXposedを強制停止してください。</string>\n    <string name=\"app_manage_repair_reboot_now\">今すぐ再起動</string>\n    <string name=\"wallpaper_too_big_tips\">選択した壁紙は大きすぎるため、起動時間が長くなる可能性があります。適切なものを選択してください。</string>\n    <string name=\"create_shortcut_already_exist\">このショートカットは既に存在します</string>\n    <string name=\"start_app_failed\">アプリを開く: %1$s 失敗しました。.</string>\n    <string name=\"app_manage_redirect_on\">オープンストレージリダイレクト</string>\n    <string name=\"app_manage_redirect_off\">ストレージリダイレクトを無効にする</string>\n    <string name=\"app_manage_redirect_desc\">ストレージリダイレクションは、アプリケーションのアクセスを実際のSDカードから仮想SDカードにリダイレクトします。これにより、特定のアプリが実際のSDカードにディレクトリを作成することを防ぎます。 ただし、ストレージリダイレクトが有効になると、アプリケーションは実際のSDカードにアクセスできなくなります。 メッセージが表示されたら選択してください。</string>\n    <string name=\"app_manage_redirect_on_confirm\">開く、確認する</string>\n    <string name=\"app_manage_redirect_off_confirm\">閉じる、確認する</string>\n    <string name=\"shared_to_vxp\">VirtualXposedでアプリを共有する</string>\n    <string name=\"shared_to_vxp_failed\">共有に失敗しました。もう一度やり直してください。</string>\n    <string name=\"app_installer_label\">VirtualXposedに追加</string>\n    <string name=\"install_complete\">完了</string>\n    <string name=\"install_fail\">%1$s インストール失敗</string>\n    <string name=\"install\">インストール</string>\n    <string name=\"install_package\">%s 新しいアプリをインストール</string>\n    <string name=\"install_package_version_tips\">既存のアプリを選択しました。\\n（インストール済みバージョン：%1$s、選択したバージョン：%2$s）。 それをインストールしますか？</string>\n    <string name=\"settings_add_app_summary\">最初にアプリとXposedモジュールの両方をVirtualXposedに追加してください。そうでない場合はXposedモジュールは有効になりません。</string>\n    <string name=\"settings_advance\">高度な設定</string>\n    <string name=\"advance_settings_hide_settings\">デスクトップの設定ボタンを隠す</string>\n    <string name=\"advance_settings_disable_installer\">システムのapkインストーラを無効にする</string>\n    <string name=\"advance_settings_hide_settings_summary\">メインアクティビティのメニューキーで設定を入力できる場合は、これを非表示にすることができます。 それ以外の場合は設定を入力できない可能性があります。 \\n（VirtualXposedを再起動して有効にしてください。）</string>\n    <string name=\"advance_settings_disable_installer_summary\">システムでapkファイルを選択したときにVirtualXposedのインストーラを表示しない</string>\n    <string name=\"advance_settings_directly_back\">直接戻る</string>\n    <string name=\"advance_settings_directly_back_summary\">仮想アプリで仮想ランチャーの代わりにシステムランチャーに戻ります。\\n（有効にするにはVirtualXposedを再起動してください。）</string>\n    <string name=\"install_self_eggs\">少年、あなたの考えは有望です</string>\n    <string name=\"advance_settings_install_gms\">Googleサービスのインストール/アンインストール</string>\n    <string name=\"about_feedback_tel_title\">Telegram グループ: %1$s</string>\n    <string name=\"advance_settings_copy_file\">ファイルをコピー</string>\n    <string name=\"about_website_title\">公式ウェブサイト</string>\n    <string name=\"about_feedback_title\">フィードバック</string>\n    <string name=\"about_feedback_hint\">お使いの携帯電話のモデル、Androidのバージョン、Xposedプラグイン、対応するアプリケーションのバージョンを指定してから、発生している問題をできるだけ詳細に説明してください。そうしないと無効なフィードバックと見なされます。 トラブルシューティングし、唯一の「このアプリがクラッシュします」で上記の問題を解決します。</string>\n    <string name=\"settings_plugin_recommend\">推奨Xposedモジュール</string>\n    <string name=\"advance_settings_disable_resident_notification\">持続通知を無効にする</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">VirtualXposedの永続通知を無効にします。 （無効にすると、VirtualXposedはシステムによって頻繁にkillされるかもしれません。注意して使ってください！）</string>\n    <string name=\"settings_module_manage\">Xposedモジュールを管理</string>\n    <string name=\"settings_module_manage_summary\">Xposedモジュールを有効/無効にする（有効にするには手動で有効にする必要があります）</string>\n    <string name=\"xposed_installer_not_found\">Xposedインストーラが見つかりません。最初にVirtualXposedに追加してください。</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">有効にすると、署名のないapkをインストールすることができます（通常、クラックされた/変更されたアプリに適用されます。注意してください。\n）</string>\n    <string name=\"advance_settings_allow_fake_signature\">署名なしでapkをインストールすることを許可します。</string>\n    <string name=\"permission_tip_title\">重要なヒント:</string>\n    <string name=\"permission_tips_content\">%1$s  ランタイムパーミッションをサポートしていません、あなたはそれが必要とするパーミッションを前もって与えなければなりません、それが次のステップで要求するすべてのパーミッションを許してください、さもなければそれは適切に働かないかもしれません。</string>\n    <string name=\"permission_tips_confirm\">はい</string>\n    <string name=\"permission_denied_tips_content\">アプリ: %1$s 必要な権限を付与していません。正しく機能しない場合は、デバイスの権限管理にアクセスして権限を付与してください。</string>\n    <string name=\"list_app_access_external_storage\">外部ストレージからapkをインストールしたい場合は、VirtualXposedに許可を与えてください。</string>\n    <string name=\"install_gms_title\" >Googleサービスをインストール</string>\n    <string name=\"install_gms_content\">GoogleサービスはmicroGによってサポートされています、VirtualXposedはいくつかのファイル（2M）をダウンロードしようとしています、そしてそれはより多くのバッテリーを消費するかもしれません、あなたはそれをインストールしますか？</string>\n    <string name=\"install_gms_fail_title\">インストール失敗</string>\n    <string name=\"install_gms_fail_content\">Googleサービスのインストールが自動的に失敗した場合は、手動でインストールすることもできます。</string>\n    <string name=\"install_gms_fail_ok\">手動インストール</string>\n    <string name=\"uninstall_gms_title\">Googleサービスをアンインストール</string>\n    <string name=\"uninstall_gms_content\">Googleサービスをアンインストールしますか？ 後で再インストールできます。</string>\n    <string name=\"uninstall_gms_ok\">アンインストール、確認</string>\n    <string name=\"install_gms_alreay_installed\">Googleサービスがインストールされました。</string>\n    <string name=\"install_gms_success\">Googleサービスは正常にインストールされました。</string>\n    <string name=\"uninstall_gms_success\">Googleサービスは正常にアンインストールされました。</string>\n    <string name=\"donate_choose_title\">寄付する方法</string>\n    <string name=\"donate_bitconins_tips\">私のbitconinsアドレスはクリップボードにコピーされました。</string>\n    <string name=\"advance_settings_disable_xposed_summary\">無効にすると、Xposedモジュールはすべて有効になりません。</string>\n    <string name=\"advance_settings_disable_xposed\">Xposedを無効にする</string>\n    <string name=\"prepare_xposed_installer\">Xposed環境を準備しています。しばらくお待ちください…</string>\n    <string name=\"settings_file_manage_text\">ファイルマネージャー</string>\n    <string name=\"install_file_manager_tips\">ファイルマネージャはAmazeファイルマネージャでサポートされています。（約3M）をダウンロードして今すぐインストールしますか？</string>\n    <string name=\"settings_permission_manage_text\">パーミッションマネージャー</string>\n    <string name=\"install_permission_manager_tips\">パーミッションマネージャーはXPrivacyLuaによって実装され、ダウンロード（約1.7M）して今すぐインストールしますか？</string>\n    <string name=\"exp_tips\">昔、私はEXposedについての情報を明らかにしました。 フィードバックと調整の期間を経て、Exposedはマイルストーンに達しました。 多くのユーザーはそれを知らないかもしれません、今日あなたに紹介させてください。 \\n\\n\n\n私が以前に作成したVirtualXposedのように、EXposedはあなたがrootなしでXposedモジュールを使用するようにするアプリでもあり、ブートローダをアンロックします。 どちらにも独自の利点があり、ネイティブシステムで直接実行することで、パフォーマンスと安定性の面でExposedの方がはるかに優れています。 VirtualXposedは、Parallel SpaceのようなVitualAppに基づいています。 EXposedは1か月で生まれました、そしてその安定性はほぼ1年間開発されてきたVirtualXposedを超えました。 \\n\\n\n\n現在、ExposedはApp Storeに置かれ、Tai Chiに改名されました。 試してみることができます。</string>\n    <string name=\"advance_settings_enable_launcher_summary\">有効にすると、VirtualXposedをシステムのランチャーに設定できます。</string>\n    <string name=\"advance_settings_enable_launcher\">ランチャーを有効にする</string>\n    <string name=\"exp_introduce_title\">Xposedを使う簡単な方法</string>\n    <string name=\"exp_introduce_install\">試してみる</string>\n    <string name=\"what_is_exp\">TaiChiって何？</string>\n    <string name=\"install_choose_way\">インストール方法を選択</string>\n    <string name=\"install_choose_content\" >VirtualXposed以外のTaiChiを介してXposedモジュールを使用できます。 TaiChiがはるかに安定している間VirtualXposedはVirtual-Appをサポートします。</string>\n    <string name=\"install_choose_taichi\">TaiChi</string>\n    <string name=\"install_taichi_not_exist\">TaiChiはインストールされていません！</string>\n    <string name=\"install_go_to_install_exp\">TaiChiのインストール</string>\n    <string name=\"install_taichi_while_old_version\">インストールされているTaiChiのバージョンが古すぎます。最新のTaichiをインストールしてください。</string>\n    <string name=\"install_go_latest_exp\">最新のTaiChiをインストール</string>\n    <string name=\"install_complete_and_open\">開く</string>\n    <string name=\"unsupported_for_32bit_app\">32ビットアプリケーションはサポートされていません。</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-pt-rBR/strings.xml",
    "content": "<resources>\n    \n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"vxp\">VirtualXposed</string>\n    <string name=\"wait\">Por favor, espere…</string>\n    <string name=\"desktop\">Área de Trabalho</string>\n    <string name=\"add_app\">Adicionar App</string>\n    <string name=\"preparing\">Abrindo app…</string>\n    <string name=\"delete\">Excluir</string>\n    <string name=\"create_shortcut\">Criar atalho</string>\n    <string name=\"new_user\">Novo usuário</string>\n    <string name=\"enable\">Habilitar</string>\n    <string name=\"save\">Salvar</string>\n    <string name=\"save_success\">Salvo com sucesso!</string>\n    <string name=\"manufacturer\">Fabricante</string>\n    <string name=\"brand\">Marca</string>\n    <string name=\"device\">Dispositivo</string>\n    <string name=\"fake_device_info\">Informações falsas do dispositivo</string>\n    <string name=\"wifi_status\">Status Wifi</string>\n    <string name=\"config_device_info\">Informação do dispositivo</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"clone_apps\">Clone Apps</string>\n    <string name=\"external_storage\">Armazenamento externo</string>\n    <string name=\"install_d\">Instalar (%d)</string>\n    <string name=\"install_too_much_once_time\">Não mais do que 9 aplicativos podem ser escolhidos por vez!</string>\n    <string name=\"versionchecklib_confirm\">Baixar</string>\n    <string name=\"versionchecklib_cancel\">Cancelar</string>\n    <string name=\"menu_virtual_location\">Localização virtual</string>\n    <string name=\"menu_about\">Sobre</string>\n    <string name=\"menu_reboot\">Reinicie</string>\n    <string name=\"installing_tips\">Instalando %1$s…</string>\n    <string name=\"update_success_tips\">Atualização com sucesso do %1$s!</string>\n    <string name=\"install_success_tips\">O módulo Xposed não terá efeito até que você o habilite na configuração do módulo XposedInstaller.</string>\n    <string name=\"install_fail_tips\">A instalação do %1$s falhou: %2$s</string>\n    <string name=\"copy_right\" translatable=\"false\">Copyrights © %1$d</string>\n    <string name=\"about_page_description\">O VirtualXposed é um aplicativo que fornece a capacidade de usar o módulo Xposed sem precisar de acesso root, desbloquear o bootloader ou modificar a imagem do sistema.</string>\n    <string name=\"about_feedback_qq_title\">Grupo QQ (Clique para copiar o número do grupo)</string>\n    <string name=\"about_feedback_wechat_title\">Grupo WeChat (Clique para copiar)</string>\n    <string name=\"about_feedback_tips\">O número do grupo foi copiado para a área de transferência!</string>\n    <string name=\"about_version_title\">Versão: %1$s</string>\n    <string name=\"about_donate_title\">Doar</string>\n    <string name=\"reboot_tips_1\">Reinício com sucesso!</string>\n    <string name=\"reboot_tips_2\">Reinício com sucesso!</string>\n    <string name=\"reboot_tips_3\">Reinício com sucesso!</string>\n    <string name=\"meizu_device_tips_title\">Detectado o dispositivo Meizu:</string>\n    <string name=\"meizu_device_tips_content\">Nos telefones Meizu OS, você só pode adicionar um aplicativo ao VirtualXposed clonando um aplicativo existente já instalado (não é possível instalar um aplicativo no VirtualXposed por meio do sideload de um apk). Você também deve instalar o XposedInstaller manualmente, pois, ao contrário das instalações em outros telefones Android, ele não está embutido no VirtualXposed ao instalar no Meizu OS. Por favor, instale o XposedInstaller primeiro.</string>\n    <string name=\"donate_alipay\">Alipay</string>\n    <string name=\"donate_wepay\">Wechat Pay</string>\n    <string name=\"prompt_alipay_not_found\">Alipay não encontrado.</string>\n    <string name=\"prompt_wait\">Espere só um momento...</string>\n    <string name=\"donate_dialog_title\">Sobre Doar</string>\n    <string name=\"donate_dialog_content\">Manter o VirtualXposed me levou muito tempo livre, e se isso te trouxer conveniência, posso me patrocinar uma onda :)</string>\n    <string name=\"donate_dialog_yes\">Doar</string>\n    <string name=\"donate_dialog_no\">Cancelar</string>\n    <string name=\"large_app_install_tips\">A instalação pode demorar um pouco, por favor, seja paciente... :)</string>\n    <string name=\"about_icon_title\">Sobre o ícone</string>\n    <string name=\"about_icon_content\">Se você não gosta do meu novo ícone, você é sempre bem-vindo para projetar um novo ícone para o VirtualXposed ;)</string>\n    <string name=\"about_icon_yes\">Está bem</string>\n    <string name=\"create_shortcut_success\">Atalho criado com sucesso!</string>\n    <string name=\"about_thanks\">Obrigado</string>\n    <string name=\"thanks_dialog_title\">obrigado</string>\n    <string name=\"thanks_dialog_content\">Obrigado Cheney por fornecer o ícone incrível, e obrigado Pei, Peggy, e muitos outros para listar, pelo seu trabalho duro. Obrigado pelas idéias e sugestões que todos vocês forneceram, e agradecimentos especiais à YingLin por dedicar um tempo para me ajudar a alcançar meu design :)</string>\n    <string name=\"alert_for_doze_mode_title\">Dicas</string>\n    <string name=\"alert_for_doze_mode_content\">Por favor, permita que o VirtualXposed seja executado em segundo plano, caso contrário você não poderá receber notificações de alguns aplicativos virtuais.</string>\n    <string name=\"alert_for_doze_mode_yes\">Permitir</string>\n    <string name=\"alert_for_doze_mode_no\">Negar</string>\n    <string name=\"about_faq_title\">Perguntas frequentes</string>\n    <string name=\"clear_app\">Limpar\\ndados</string>\n    <string name=\"stop_app\">Força\\nParar</string>\n    <string name=\"home_menu_delete_title\">Excluir aplicativo</string>\n    <string name=\"home_menu_delete_content\">Você deseja excluir %1$s?</string>\n    <string name=\"home_menu_clear_title\">Limpar dados do aplicativo</string>\n    <string name=\"home_menu_clear_content\">Deseja limpar dados de %1$s?</string>\n    <string name=\"home_menu_kill_title\">Força Parada</string>\n    <string name=\"home_menu_kill_content\">Você quer forçar a parada do %1$s? Isso pode fazer com que ele funcione inesperadamente.</string>\n    <string name=\"add_app_loading_tips\">Pacote de análise para %1$s…</string>\n    <string name=\"add_app_installing_tips\">Instalando %1$s…</string>\n    <string name=\"add_app_loading_complete\">%1$s instalado com sucesso!</string>\n    <string name=\"list_app_activity_install\">Adicionar ao VirtualXposed</string>\n    <string name=\"settings_about_text\">Sobre</string>\n    <string name=\"settings_task_manage_text\">Gerenciar Tarefas</string>\n    <string name=\"settings_app_manage_text\">Gerenciar aplicativos</string>\n    <string name=\"settings_desktop_text\">Configurações da área de trabalho</string>\n    <string name=\"app_manage_uninstall\">Desinstalar</string>\n    <string name=\"app_manage_repair\">Reparar</string>\n    <string name=\"settings_title\">Configurações</string>\n    <string name=\"task_manage_uninstall\">Matar processo</string>\n    <string name=\"settings_reboot_title\">Reiniciar o VirtualXposed</string>\n    <string name=\"settings_reboot_content\">Isso matará todos os aplicativos atualmente em execução no VirtualXposed. Reinicie mesmo assim?</string>\n    <string name=\"check_update\">Checar atualização</string>\n    <string name=\"version_is_latest\">A versão mais recente está instalada.</string>\n    <string name=\"new_version_detected\">Nova versão:</string>\n    <string name=\"multi_version_tip_title\">Dicas de instalação</string>\n    <string name=\"multi_version_tips_content\">Você escolheu um aplicativo existente. Você quer instalá-lo como um aplicativo separado ou apenas atualizar o existente? \\ n (versão instalada%1$s, versão selecionada:% 2 $ s)</string>\n    <string name=\"multi_version_multi\">Instale outro</string>\n    <string name=\"multi_version_cover\">Tampa</string>\n    <string name=\"multi_version_upgrade\">Atualizar</string>\n    <string name=\"multi_version_downgrade\">Downgrade</string>\n    <string name=\"app_manage_repair_failed_tips\">Desculpe, o reparo falhou; por favor, reinstale este aplicativo.</string>\n    <string name=\"app_manage_repairing\">Reparando…</string>\n    <string name=\"app_manage_repair_success_title\">Dicas de reparo</string>\n    <string name=\"app_manage_repair_success_content\">Sucesso de reparo; por favor force-stop VirtualXposed para que ele tenha efeito.</string>\n    <string name=\"app_manage_repair_reboot_now\">Reinicie agora</string>\n    <string name=\"wallpaper_too_big_tips\">A imagem do papel de parede é muito grande para diminuir o tempo de inicialização, por favor, escolha uma adequada.</string>\n    <string name=\"create_shortcut_already_exist\">Este atalho já existe</string>\n    <string name=\"start_app_failed\">Falha ao abrir o aplicativo: %1$s.</string>\n    <string name=\"app_manage_redirect_on\">Ativar Redirecionamento de armazenamento</string>\n    <string name=\"app_manage_redirect_off\">Desativar o redirecionamento de armazenamento</string>\n    <string name=\"app_manage_redirect_desc\">Redirecionamento de armazenamento redireciona o acesso de um aplicativo do cartão SD real para um cartão SD virtual, o que impedirá que certos aplicativos criem diretórios em seu cartão SD real; no entanto, depois que o redirecionamento de armazenamento estiver habilitado, o aplicativo não poderá mais acessar o cartão SD real. Por favor selecione quando solicitado.</string>\n    <string name=\"app_manage_redirect_on_confirm\">Abrir, confirmar</string>\n    <string name=\"app_manage_redirect_off_confirm\">Fechar, confirmar</string>\n    <string name=\"shared_to_vxp\">Compartilhar para o aplicativo no VirtualXposed</string>\n    <string name=\"shared_to_vxp_failed\">Compartilhar falhou, tente novamente.</string>\n    <string name=\"app_installer_label\">Adicionar ao VirtualXposed</string>\n    <string name=\"install_complete\">Instalação completa.</string>\n    <string name=\"install_fail\">A instalação falhou: %1$s</string>\n    <string name=\"install\">Instalar</string>\n    <string name=\"install_package\">Instalar o novo aplicativo: %s</string>\n    <string name=\"install_package_version_tips\">Você escolheu um aplicativo existente,\\n(versão instalada %1$s, versão selecionada: %2$s). Instalar?</string>\n    <string name=\"settings_add_app_summary\">Por favor, adicione o aplicativo e o módulo Xposed ao VirtualXposed primeiro, caso contrário o módulo Xposed não terá efeito.</string>\n    <string name=\"settings_advance\">Configurações avançadas</string>\n    <string name=\"advance_settings_hide_settings\">Ocultar o botão de configurações na área de trabalho</string>\n    <string name=\"advance_settings_disable_installer\">Desativar o instalador apk para o sistema</string>\n    <string name=\"advance_settings_hide_settings_summary\">Se você pode inserir configurações pela tecla de menu na atividade principal, você pode ocultar isso; talvez você não consiga inserir as configurações de outra forma! \\n (Reinicie o VirtualXposed para entrar em vigor.)</string>\n    <string name=\"advance_settings_disable_installer_summary\">Não mostre o instalador do VirtualXposed quando você escolher o arquivo apk no sistema</string>\n    <string name=\"advance_settings_directly_back\">Diretamente de volta</string>\n    <string name=\"advance_settings_directly_back_summary\">Volte para o ativador do sistema em vez do lançador virtual quando estiver em um aplicativo virtual. \\n (Reinicie o VirtualXposed para entrar em vigor.)</string>\n    <string name=\"install_self_eggs\">Rapaz, sua ideia é promissora :)</string>\n    <string name=\"advance_settings_install_gms\">Instalar/desinstalar serviços do Google</string>\n    <string name=\"about_feedback_tel_title\">Grupo de telegramas: %1$s</string>\n    <string name=\"advance_settings_copy_file\">Copiar Arquivo</string>\n    <string name=\"about_website_title\">Website oficial</string>\n    <string name=\"about_feedback_title\">Comentários</string>\n    <string name=\"about_feedback_hint\">Especifique o modelo do seu telefone, a versão Android, o plugin Xposed e a versão do aplicativo correspondente e, em seguida, descreva (o mais detalhadamente possível) o problema que você está enfrentando, caso contrário, será considerado um feedback inválido (porque não podemos efetivamente solucionar problemas e corrigir o problema com apenas \\\"este aplicativo falha \\\";))</string>\n    <string name=\"settings_plugin_recommend\">Módulo Xposed Recomendado</string>\n    <string name=\"advance_settings_disable_resident_notification\">Desativar notificação persistente</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">Desativar a notificação persistente do VirtualXposed. (Quando desativado, o VirtualXposed pode ser morto freqüentemente pelo sistema. Por favor, seja cauteloso!)</string>\n    <string name=\"settings_module_manage\">Gerenciar o módulo Xposed</string>\n    <string name=\"settings_module_manage_summary\">Ativar/desativar o módulo Xposed (você deve ativá-lo manualmente para que ele tenha efeito)</string>\n    <string name=\"xposed_installer_not_found\">Instalador Xposed não encontrado, por favor, adicione-o ao VirtualXposed primeiro!</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">Quando ativado, você pode instalar apk que não tem assinaturas (geralmente usado em apk crackeado, por favor, tenha cuidado )</string>\n    <string name=\"advance_settings_allow_fake_signature\">Permitir instalar apk sem assinaturas.</string>\n    <string name=\"permission_tip_title\">Dicas importantes:</string>\n    <string name=\"permission_tips_content\">%1$s não suporta a permissão de tempo de execução, você deve conceder permissões que precisa com antecedência, por favor, permita toda a permissão que será solicitada na próxima etapa, caso contrário, ela pode não funcionar corretamente.</string>\n    <string name=\"permission_tips_confirm\">OK, eu sei.</string>\n    <string name=\"permission_denied_tips_content\">App: %1$s não concede a permissão necessária, se ela não funcionar corretamente, acesse o gerenciamento de permissões do seu dispositivo e conceda-lhe permissões.</string>\n    <string name=\"list_app_access_external_storage\">Se você quiser instalar apk de armazenamento externo, por favor, dê VirtualXposed a permissão.</string>\n    <string name=\"install_gms_title\">Instalar o serviço do Google</string>\n    <string name=\"install_gms_content\">O Serviço Google é suportado pelo microG, o VirtualXposed está prestes a baixar algum arquivo (2M), e pode consumir mais bateria, você gostaria de instalá-lo?</string>\n    <string name=\"install_gms_fail_title\">Instalação falhou</string>\n    <string name=\"install_gms_fail_content\">falha ao instalar o serviço do Google automaticamente, você também pode instalá-lo manualmente.</string>\n    <string name=\"install_gms_fail_ok\">Instalação Manual</string>\n    <string name=\"uninstall_gms_title\">Desinstalar o serviço do Google</string>\n    <string name=\"uninstall_gms_content\">Deseja desinstalar o serviço do Google? você pode reinstalá-lo mais tarde.</string>\n    <string name=\"uninstall_gms_ok\">Desinstalar, confirmar</string>\n    <string name=\"install_gms_alreay_installed\">O serviço do Google foi instalado.</string>\n    <string name=\"install_gms_success\">O serviço do Google foi instalado com sucesso !!</string>\n    <string name=\"uninstall_gms_success\">O serviço do Google foi desinstalado com sucesso !!</string>\n    <string name=\"donate_choose_title\">Maneira de doar</string>\n    <string name=\"donate_bitconins_tips\">Meu endereço bitconins foi copiado para a área de transferência :)</string>\n    <string name=\"advance_settings_disable_xposed_summary\">Quando desativado, todo o módulo Xposed não terá efeito.</string>\n    <string name=\"advance_settings_disable_xposed\">Desativar Xposed</string>\n    <string name=\"prepare_xposed_installer\">Preparando o ambiente Xposed, por favor aguarde ...</string>\n    <string name=\"settings_file_manage_text\">Gerenciar arquivos</string>\n    <string name=\"install_file_manager_tips\">Gerenciador de arquivos é suportado pelo Amaze File Manager, download (cerca de 3M) e instalá-lo agora?</string>\n    <string name=\"settings_permission_manage_text\">Gerenciador de permissões</string>\n    <string name=\"install_permission_manager_tips\">Gerenciador de permissões é implementado pelo XPrivacyLua, baixar (cerca de 1.7M) e instalá-lo agora?</string>\n    <string name=\"advance_settings_enable_launcher_summary\">Enable Launcher</string>\n    <string name=\"advance_settings_enable_launcher\">Enable Launcher</string>\n    <string name=\"install_complete_and_open\">Aberto</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string name=\"app_name\">VirtualXposed</string>\n\t<string name=\"wait\">Подождите…</string>\n\t<string name=\"desktop\">Рабочий стол</string>\n\t<string name=\"add_app\">Добавить приложение</string>\n\t<string name=\"preparing\">Открытие приложения...</string>\n\t<string name=\"delete\">Удалить</string>\n\t<string name=\"create_shortcut\">Создать ярлык</string>\n\t<string name=\"new_user\">Новый пользователь</string>\n\t<string name=\"enable\">Включить</string>\n\t<string name=\"save\">Сохранить</string>\n\t<string name=\"save_success\">Сохранение завершено!</string>\n\t<string name=\"manufacturer\">Производитель</string>\n\t<string name=\"brand\">Бренд</string>\n\t<string name=\"device\">Устройство</string>\n\t<string name=\"fake_device_info\">Фиктивная информация об устройстве</string>\n\t<string name=\"wifi_status\">Состояние Wifi</string>\n\t<string name=\"config_device_info\">Информация об устройстве</string>\n\t<string name=\"about\">О приложении</string>\n\t<string name=\"clone_apps\">Клонирование приложений</string>\n\t<string name=\"external_storage\">Внешнее хранилище</string>\n\t<string name=\"install_d\">Установить (%d)</string>\n\t<string name=\"install_too_much_once_time\">За один раз можно выбрать не более 9 приложений!</string>\n\t<string name=\"versionchecklib_confirm\">Скачать</string>\n\t<string name=\"versionchecklib_cancel\">Отмена</string>\n\t<string name=\"menu_virtual_location\">Виртуальное местоположение</string>\n\t<string name=\"menu_about\">О приложении</string>\n\t<string name=\"menu_reboot\">Перезагрузка</string>\n\t<string name=\"installing_tips\">Установка %1$s…</string>\n\t<string name=\"update_success_tips\">Обновление %1$s успешно!</string>\n\t<string name=\"install_success_tips\">Модуль Xposed не будет действовать, пока вы не включите его в настройках модуля XposedInstaller.</string>\n\t<string name=\"install_fail_tips\">Установка %1$s ошибка: %2$s</string>\n\t<string name=\"about_page_description\">VirtualXposed - это приложение, которое обеспечивает возможность использования модуля Xposed без необходимости доступа к рут, разблокировки загрузчика или изменения образа системы.</string>\n\t<string name=\"about_feedback_qq_title\">QQ Group (нажмите, чтобы скопировать номер группы)</string>\n\t<string name=\"about_feedback_wechat_title\">WeChat Group (нажмите, чтобы скопировать)</string>\n\t<string name=\"about_feedback_tips\">Номер группы скопирован в буфер обмена!</string>\n\t<string name=\"about_version_title\">Версия: %1$s</string>\n\t<string name=\"about_donate_title\">Пожертвовать</string>\n\t<string name=\"reboot_tips_1\">Успешная перезагрузка!</string>\n\t<string name=\"reboot_tips_2\">Успешная перезагрузка!</string>\n\t<string name=\"reboot_tips_3\">Успешная перезагрузка!</string>\n\t<string name=\"meizu_device_tips_title\">Обнаружение устройства Meizu:</string>\n\t<string name=\"meizu_device_tips_content\">\"В телефонах Meizu OS вы можете добавлять приложение в VirtualXposed, клонируя существующее приложение, которое уже установлено (вы не можете установить приложение в VirtualXposed через загрузку apk). Вы также должны установить XposedInstaller вручную, так как, в отличие от установок на другом Android телефоне, он не встроен в VirtualXposed при установке на Meizu OS.  Сначала установите XposedInstaller.\"</string>\n\t<string name=\"prompt_alipay_not_found\">Alipay не найден.</string>\n\t<string name=\"prompt_wait\">Подождите минуту...</string>\n\t<string name=\"donate_dialog_title\">О пожертвовании</string>\n\t<string name=\"donate_dialog_content\">Поддержание VirtualXposed отнимает у меня много времени, если вы цените мою работу, купите мне чашку кофе! :)</string>\n\t<string name=\"donate_dialog_yes\">Пожертвовать</string>\n\t<string name=\"donate_dialog_no\">Отмена</string>\n\t<string name=\"large_app_install_tips\">Установка может занять некоторое время, будьте терпеливы... :)</string>\n\t<string name=\"about_icon_title\">О значке</string>\n\t<string name=\"about_icon_content\">Если не нравится мой новый значок, вы всегда можете создать новый значок для VirtualXposed;)</string>\n\t<string name=\"about_icon_yes\">ОК</string>\n\t<string name=\"create_shortcut_success\">Ярлык успешно создан!</string>\n\t<string name=\"about_thanks\">Спасибо</string>\n\t<string name=\"thanks_dialog_title\">Спасибо</string>\n\t<string name=\"alert_for_doze_mode_title\">Подсказки</string>\n\t<string name=\"alert_for_doze_mode_content\">Разрешите VirtualXposed работать в фоновом режиме, в противном случае вы не сможете получать уведомления от некоторых виртуальных приложений.</string>\n\t<string name=\"alert_for_doze_mode_yes\">Разрешить</string>\n\t<string name=\"alert_for_doze_mode_no\">Запретить</string>\n\t<string name=\"clear_app\">\"Очистить \nданные\"</string>\n\t<string name=\"stop_app\">\"Принудительная \nостановка\"</string>\n\t<string name=\"home_menu_delete_title\">Удалить приложение</string>\n\t<string name=\"home_menu_delete_content\">Удалить %1$s ?</string>\n\t<string name=\"home_menu_kill_title\">Принудительная остановка</string>\n\t<string name=\"home_menu_kill_content\">Хотите принудительно остановить %1$s ? Это может привести к сбоям</string>\n\t<string name=\"add_app_loading_tips\">Разбор пакета для %1$s…</string>\n\t<string name=\"add_app_installing_tips\">Установка %1$s…</string>\n\t<string name=\"add_app_loading_complete\">%1$s успешно установлено!</string>\n\t<string name=\"list_app_activity_install\">Добавить в VirtualXposed</string>\n\t<string name=\"settings_about_text\">О приложении</string>\n\t<string name=\"settings_task_manage_text\">Управление задачами</string>\n\t<string name=\"settings_app_manage_text\">Управление приложениями</string>\n\t<string name=\"settings_desktop_text\">Настройки</string>\n\t<string name=\"app_manage_uninstall\">Удаление</string>\n\t<string name=\"app_manage_repair\">Исправить</string>\n\t<string name=\"settings_title\">Настройки</string>\n\t<string name=\"task_manage_uninstall\">Уничтожить процесс</string>\n\t<string name=\"settings_reboot_title\">Перезагрузка VirtualXposed</string>\n\t<string name=\"settings_reboot_content\">Это уничтожит все приложения, которые в настоящее время работают в VirtualXposed. Перезагрузить всё равно?</string>\n\t<string name=\"check_update\">Проверить обновление</string>\n\t<string name=\"version_is_latest\">Установлена ​​последняя версия.</string>\n\t<string name=\"new_version_detected\">Новая версия:</string>\n\t<string name=\"multi_version_tip_title\">Советы по установке</string>\n\t<string name=\"multi_version_tips_content\">\"Вы выбрали существующее приложение. Хотите установить его как отдельное приложение или просто обновить существующее?\n(Установленная версия %1$s, Выбранная версия: %2$s)\"</string>\n\t<string name=\"multi_version_multi\">Установить еще один</string>\n\t<string name=\"multi_version_cover\">Обложка</string>\n\t<string name=\"multi_version_upgrade\">Обновить</string>\n\t<string name=\"multi_version_downgrade\">Понизить версию</string>\n\t<string name=\"app_manage_repairing\">Исправление...</string>\n\t<string name=\"app_manage_repair_success_title\">Советы по исправлению</string>\n\t<string name=\"app_manage_repair_success_content\">Успешное исправление; принудительно остановите VirtualXposed, чтобы оно вступило в силу.</string>\n\t<string name=\"app_manage_repair_reboot_now\">Перезагрузить сейчас</string>\n\t<string name=\"wallpaper_too_big_tips\">Изображение обоев слишком велико, может замедлить время запуска, выберите подходящее.</string>\n\t<string name=\"create_shortcut_already_exist\">Этот ярлык уже существует</string>\n\t<string name=\"start_app_failed\">Открыть приложение: %1$s не удалось.</string>\n\t<string name=\"app_manage_redirect_on\">Открыть перенаправление хранилища</string>\n\t<string name=\"app_manage_redirect_off\">Отключить перенаправление хранилища</string>\n\t<string name=\"app_manage_redirect_desc\">Перенаправление хранилища перенаправляет доступ приложения с реальной SD карты на виртуальную SD карту, что не позволит некоторым приложениям создавать каталоги на вашей реальной SD карте; однако после включения перенаправления хранилища приложение больше не может получить доступ к реальной SD карте. Выберите его при появлении запроса.</string>\n\t<string name=\"app_manage_redirect_on_confirm\">Открыть, Подтвердить</string>\n\t<string name=\"app_manage_redirect_off_confirm\">Закрыть, Подтвердить</string>\n\t<string name=\"shared_to_vxp\">Общий доступ к приложению в VirtualXposed</string>\n\t<string name=\"shared_to_vxp_failed\">Не удалось выполнить общий доступ, повторите попытку.</string>\n\t<string name=\"app_installer_label\">Добавить в VirtualXposed</string>\n\t<string name=\"install_complete\">Установка завершена.</string>\n\t<string name=\"install_fail\">Ошибка установки: %1$s</string>\n\t<string name=\"install\">Установить</string>\n\t<string name=\"install_package\">Установить новое приложение: %s</string>\n\t<string name=\"install_package_version_tips\">\"Вы выбрали существующее приложение,\n(Установленная версия %1$s, выбранная версия: %2$s). Установить? \"</string>\n\t<string name=\"settings_add_app_summary\">Сначала добавьте приложение и модуль Xposed в VirtualXposed, иначе модуль Xposed не вступит в силу.</string>\n\t<string name=\"settings_advance\">Дополнительные настройки</string>\n\t<string name=\"advance_settings_hide_settings\">Скрыть кнопку настроек на рабочем столе</string>\n\t<string name=\"advance_settings_disable_installer\">Отключить установщик apk для системы</string>\n\t<string name=\"advance_settings_hide_settings_summary\">\"Если сможете ввести настройки с помощью клавиши меню в основном действии, можете скрыть это: вы не сможете вводить настройки в противном случае!\n(Перезапустите VirtualXposed, чтобы вступило в силу.) \"</string>\n\t<string name=\"advance_settings_disable_installer_summary\">Не показывать установщик VirtualXposed, когда вы выбираете файл apk в системе</string>\n\t<string name=\"advance_settings_directly_back\">Непосредственно назад</string>\n\t<string name=\"advance_settings_directly_back_summary\">\"Вернитесь к системному лаунчеру вместо виртуального лаунчера, когда находитесь в виртуальном приложении.\n(Перезапустите VirtualXposed, чтобы вступило в силу.) \"</string>\n\t<string name=\"install_self_eggs\">Твоя идея многообещающая :)</string>\n\t<string name=\"advance_settings_install_gms\">Установите Google Services</string>\n\t<string name=\"advance_settings_copy_file\">Копировать файл</string>\n\t<string name=\"about_website_title\">Официальный сайт</string>\n\t<string name=\"about_feedback_title\">Отзывы</string>\n\t<string name=\"about_feedback_hint\">Укажите модель телефона, версию Android, плагин Xposed и версию соответствующего приложения, а затем опишите (как можно более подробно) проблему, которую вы испытываете, в противном случае она считается недействительной обратной связью (потому что мы не можем эффективно устранить и исправить указанную проблему только с \\\"приложение глюкануло\\\" ;) )</string>\n\t<string name=\"settings_plugin_recommend\">Рекомендуемый модуль Xposed</string>\n\t<string name=\"advance_settings_disable_resident_notification\">Отключить уведомление резидента</string>\n\t<string name=\"advance_settings_disable_resident_notification_summary\">Отключите резидентное уведомление VirtualXposed. (Если отключено, VirtualXposed может быть часто уничтожен системой. Будьте осторожны!)</string>\n\t<string name=\"settings_module_manage\">Управление модулем Xposed</string>\n\t<string name=\"settings_module_manage_summary\">Включить/Отключить модуль Xposed (вы должны включить его вручную, чтобы он вступил в силу)</string>\n\t<string name=\"xposed_installer_not_found\">Инсталлятор Xposed, не найден,сначала добавьте его в VirtualXposed!</string>\n\t<string name=\"advance_settings_allow_fake_signature_summary\">Когда включено, вы можете установить apk, у которого нет подписи (обычно используется в взломаных apk, будьте осторожны)</string>\n\t<string name=\"advance_settings_allow_fake_signature\">Разрешить установку apk без подписи.</string>\n\t<string name=\"thanks_dialog_content\">Спасибо Чейни за предоставление удивительного значка, и спасибо Пей, Пегги ,papasha55 и многим другим, всех не перечислить, за их трудную работу. Спасибо за идеи и предложения, которые вы все предоставили, и особая благодарность YingLin за то, что нашёл время, чтобы помочь мне сделать дизайн :)</string>\n\t<string name=\"home_menu_clear_title\">Очистить данные приложения</string>\n\t<string name=\"home_menu_clear_content\">Очистить данные %1$s ?</string>\n\t<string name=\"app_manage_repair_failed_tips\">Исправление не удалось; переустановите это приложение.</string>\n        <string name=\"settings_file_manage_text\">Файловый менеджер</string>\n        <string name=\"install_file_manager_tips\">Файловый менеджер поддерживается Amaze File Manager, скачать(около 3МБ) и установить сейчас?</string>\n        <string name=\"settings_permission_manage_text\">Управление разрешениями</string>\n        <string name=\"install_permission_manager_tips\">Управление разрешениями реализовано XPrivacyLua, скачать(около 1.7МБ) и установить сейчас?</string>\n\t<string name=\"advance_settings_enable_launcher_summary\">Когда включен, Вы можете выбрать VirtualXposed как лаунчер по умолчанию для системы</string>\n        <string name=\"advance_settings_enable_launcher\">Включить лаунчер</string>\n\t<string name=\"advance_settings_disable_xposed_summary\">Когда отключен, все Xposed модули не будут работать.</string>\n        <string name=\"advance_settings_disable_xposed\">Отключить Xposed</string>\n    <string name=\"install_complete_and_open\">открытый</string>\n    <string name=\"unsupported_for_32bit_app\">32-битные приложения не поддерживаются!</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string name=\"app_name\">VirtualXposed</string>\n\t<string name=\"wait\">Зачекайте…</string>\n\t<string name=\"desktop\">Робочий стіл</string>\n\t<string name=\"add_app\">Додати додаток</string>\n\t<string name=\"preparing\">Відкриваємо додаток...</string>\n\t<string name=\"delete\">Видалити</string>\n\t<string name=\"create_shortcut\">Створити ярлик</string>\n\t<string name=\"new_user\">Новий користувач</string>\n\t<string name=\"enable\">Увімкнути</string>\n\t<string name=\"save\">Зберегти</string>\n\t<string name=\"save_success\">Збереження завершено!</string>\n\t<string name=\"manufacturer\">Виробник</string>\n\t<string name=\"brand\">Бренд</string>\n\t<string name=\"device\">Пристрій</string>\n\t<string name=\"fake_device_info\">Фіктивна інформація про пристрій</string>\n\t<string name=\"wifi_status\">Стан Wifi</string>\n\t<string name=\"config_device_info\">Інформація про пристрій</string>\n\t<string name=\"about\">Про додаток</string>\n\t<string name=\"clone_apps\">Клонування додатків</string>\n\t<string name=\"external_storage\">Зовнішнє сховище</string>\n\t<string name=\"install_d\">Встановити (%d)</string>\n\t<string name=\"install_too_much_once_time\">За один раз можна вибрати не більше 9 додатків!</string>\n\t<string name=\"versionchecklib_confirm\">Скачати</string>\n\t<string name=\"versionchecklib_cancel\">Скасувати</string>\n\t<string name=\"menu_virtual_location\">Віртуальне місцезнаходження</string>\n\t<string name=\"menu_about\">Про додаток</string>\n\t<string name=\"menu_reboot\">Перезавантажити</string>\n\t<string name=\"installing_tips\">Встановлення %1$s…</string>\n\t<string name=\"update_success_tips\">Оновлення %1$s успішно!</string>\n\t<string name=\"install_success_tips\">Модуль Xposed не діятиме, поки ви не включите його в настройках модуля XposedInstaller.</string>\n\t<string name=\"install_fail_tips\">Встановлення %1$s помилка: %2$s</string>\n\t<string name=\"about_page_description\">VirtualXposed - це програма, яка забезпечує можливість використання модуля Xposed без необхідності доступу до рут, розблокування завантажувача або зміни образу системи.</string>\n\t<string name=\"about_feedback_qq_title\">QQ Group (натисніть, щоб скопіювати номер групи)</string>\n\t<string name=\"about_feedback_wechat_title\">WeChat Group (натисніть, щоб скопіювати)</string>\n\t<string name=\"about_feedback_tips\">Номер групи скопійований в буфер обміну!</string>\n\t<string name=\"about_version_title\">Версія: %1$s</string>\n\t<string name=\"about_donate_title\">Пожертвувати</string>\n\t<string name=\"reboot_tips_1\">Успішний перезапуск!</string>\n\t<string name=\"reboot_tips_2\">Успішний перезапуск!</string>\n\t<string name=\"reboot_tips_3\">Успішний перезапуск!</string>\n\t<string name=\"meizu_device_tips_title\">Виявлення пристрою Meizu:</string>\n\t<string name=\"meizu_device_tips_content\">\"В телефонах Meizu OS ви можете додавати додаток в VirtualXposed, клонуючи існуючу програму, яка вже встановлена (ви не можете встановити додаток в VirtualXposed через завантаження apk).  Ви також повинні встановити XposedInstaller вручну, так як, на відміну від встановлення на іншому Android телефоні, він не вбудований в VirtualXposed при встановленні на Meizu OS.  Спочатку встановіть XposedInstaller.\"</string>\n\t<string name=\"prompt_alipay_not_found\">Alipay не знайдений.</string>\n\t<string name=\"prompt_wait\">Зачекайте хвилинку...</string>\n\t<string name=\"donate_dialog_title\">Про пожертвування</string>\n\t<string name=\"donate_dialog_content\">Підтримка VirtualXposed забирає у мене багато часу, якщо ви цінуєте мою роботу, купіть мені чашечку кави! :)</string>\n\t<string name=\"donate_dialog_yes\">Пожертвувати</string>\n\t<string name=\"donate_dialog_no\">Скасувати</string>\n\t<string name=\"large_app_install_tips\">Встановлення може зайняти деякий час, будьте терплячі... :)</string>\n\t<string name=\"about_icon_title\">Про іконку</string>\n\t<string name=\"about_icon_content\">Якщо не подобається мій новий значок, ви завжди можете створити новий значок для VirtualXposed;)</string>\n\t<string name=\"about_icon_yes\">ОК</string>\n\t<string name=\"create_shortcut_success\">Ярлик успішно створений!</string>\n\t<string name=\"about_thanks\">Подяки</string>\n\t<string name=\"thanks_dialog_title\">Подяки</string>\n    <string name=\"thanks_dialog_content\" >Дякую Cheney за надану приголомшливу іконку, а також дякую Pei, Peggy, та багатьом іншим, за вашу нелегку працю.  Дякую за всі запропоновані вами ідеї та пропозиції та особливу подяку YingLin за те, що він знайшов час, щоб допомогти мені цього дизайну :)\nПереклав на українську: Вадим Титан</string>\n    <string name=\"alert_for_doze_mode_title\">Підказки</string>\n\t<string name=\"alert_for_doze_mode_content\">Дозвольте VirtualXposed працювати у фоновому режимі, в іншому випадку ви не зможете отримувати повідомлення від деяких віртуальних додатків.</string>\n\t<string name=\"alert_for_doze_mode_yes\">Дозволити</string>\n\t<string name=\"alert_for_doze_mode_no\">Заборонити</string>\n\t<string name=\"clear_app\">\"Очистити \nдані\"</string>\n\t<string name=\"stop_app\">\"Примусова \nзупинка\"</string>\n\t<string name=\"home_menu_delete_title\">Видалити додаток</string>\n\t<string name=\"home_menu_delete_content\">Видалити %1$s ?</string>\n\t<string name=\"home_menu_clear_title\">Очистити дані додатку</string>\n\t<string name=\"home_menu_clear_content\">Очистити дані %1$s ?</string>\n    <string name=\"home_menu_kill_title\">Примусова зупинка</string>\n\t<string name=\"home_menu_kill_content\">Хочете примусово зупинити %1$s ? Це може привести до збоїв</string>\n\t<string name=\"add_app_loading_tips\">Розбір пакета для %1$s…</string>\n\t<string name=\"add_app_installing_tips\">Встановлення %1$s…</string>\n\t<string name=\"add_app_loading_complete\">%1$s успішно встановлено!</string>\n\t<string name=\"list_app_activity_install\">Додати в VirtualXposed</string>\n\t<string name=\"settings_about_text\">Про додаток</string>\n\t<string name=\"settings_task_manage_text\">Керування задачами</string>\n\t<string name=\"settings_app_manage_text\">Керування додатками</string>\n\t<string name=\"settings_desktop_text\">Налаштування</string>\n\t<string name=\"app_manage_uninstall\">Видалити</string>\n\t<string name=\"app_manage_repair\">Виправити</string>\n\t<string name=\"settings_title\">Налаштування</string>\n\t<string name=\"task_manage_uninstall\">Знищити процес</string>\n\t<string name=\"settings_reboot_title\">Перезавантаження VirtualXposed</string>\n\t<string name=\"settings_reboot_content\">Це знищить всі процеси, які в даний час працюють в VirtualXposed. Перезавантажити все одно?</string>\n\t<string name=\"check_update\">Перевірити оновлення</string>\n\t<string name=\"version_is_latest\">Встановлена остання версія.</string>\n\t<string name=\"new_version_detected\">Нова версія:</string>\n\t<string name=\"multi_version_tip_title\">Поради по встановленню</string>\n\t<string name=\"multi_version_tips_content\">\"Ви вибрали існуючий додаток. Хочете встановити його як окремий додаток або просто оновити існуючий?\n(Встановлена ​​версія %1$s, Обрана версія: %2$s)\"</string>\n\t<string name=\"multi_version_multi\">Встановити ще один</string>\n\t<string name=\"multi_version_cover\">Обкладинка</string>\n\t<string name=\"multi_version_upgrade\">Оновити</string>\n\t<string name=\"multi_version_downgrade\">Понизити версію</string>\n\t<string name=\"app_manage_repair_failed_tips\" >На жаль, виправлення не вдалося;  перевстановіть цей додаток.</string>\n    <string name=\"app_manage_repairing\">Виправлення...</string>\n\t<string name=\"app_manage_repair_success_title\">Поради щодо виправлення</string>\n\t<string name=\"app_manage_repair_success_content\">Успішне виправлення; примусово зупиніть VirtualXposed, щоб воно вступило в силу.</string>\n\t<string name=\"app_manage_repair_reboot_now\">Перезавантажити зараз</string>\n\t<string name=\"wallpaper_too_big_tips\">Зображення шпалер занадто велике, може уповільнити час запуску, виберіть відповідніше.</string>\n\t<string name=\"create_shortcut_already_exist\">Цей ярлик вже існує</string>\n\t<string name=\"start_app_failed\">Відкрити додаток: %1$s не вдалося.</string>\n\t<string name=\"app_manage_redirect_on\">Ввімкнути перенаправлення сховища</string>\n\t<string name=\"app_manage_redirect_off\">Вимкнути перенаправлення сховища</string>\n\t<string name=\"app_manage_redirect_desc\">Перенаправлення сховища перенаправляє доступ додатки з реальної SD карти на віртуальну SD карту, що не дозволить деяким додаткам створювати каталоги на вашій реальній SD карті;  проте після включення перенаправлення сховища додаток більше не може отримати доступ до реальної SD карти.  Виберіть його у разі запиту.</string>\n\t<string name=\"app_manage_redirect_on_confirm\">Відкрити, Підтвердити</string>\n\t<string name=\"app_manage_redirect_off_confirm\">Закрити, Підтвердити</string>\n\t<string name=\"shared_to_vxp\">Загальний доступ до додатку в VirtualXposed</string>\n\t<string name=\"shared_to_vxp_failed\">Не вдалося виконати загальний доступ, спробуйте ще раз.</string>\n\t<string name=\"app_installer_label\">Додати в VirtualXposed</string>\n\t<string name=\"install_complete\">Встановлення завершене.</string>\n\t<string name=\"install_fail\">Помилка встановлення: %1$s</string>\n\t<string name=\"install\">Встановити</string>\n\t<string name=\"install_package\">Встановити новий додаток: %s</string>\n\t<string name=\"install_package_version_tips\">\"Ви вибрали існуючий додаток,\n(Встановлена ​​версія %1$s, обрана версія: %2$s). Встановити? \"</string>\n\t<string name=\"settings_add_app_summary\">Спочатку додайте додаток і модуль Xposed в VirtualXposed, інакше модуль Xposed не вступить в силу.</string>\n\t<string name=\"settings_advance\">Додаткові налаштування</string>\n\t<string name=\"advance_settings_hide_settings\">Приховати кнопку налаштувань на робочому столі</string>\n\t<string name=\"advance_settings_disable_installer\">Відключити встановлювач apk для системи</string>\n\t<string name=\"advance_settings_hide_settings_summary\">\"Якщо зможете ввести настройки за допомогою клавіші меню в основні дії, можете приховати це: ви не зможете змінювати налаштування в іншому випадку!\n(Перезапустіть VirtualXposed, щоб зміни вступили в силу.) \"</string>\n\t<string name=\"advance_settings_disable_installer_summary\">Не показувати встановлювач VirtualXposed, коли ви вибираєте файл apk в системі</string>\n\t<string name=\"advance_settings_directly_back\">Безпосередньо назад</string>\n\t<string name=\"advance_settings_directly_back_summary\">\"Поверніться до системного лаунчера замість віртуального лаунчера, коли перебуваєте у віртуальному додатку.\n(Перезапустіть VirtualXposed, щоб зміни вступили в силу.) \"</string>\n\t<string name=\"install_self_eggs\">Твоя ідея багатообіцяюча :)</string>\n\t<string name=\"advance_settings_install_gms\">Встановити/Видалити Google Services</string>\n\t<string name=\"about_feedback_tel_title\">Група Telegram (англ./кит.): %1$s</string>\n    <string name=\"advance_settings_copy_file\">Копіювати файл</string>\n\t<string name=\"about_website_title\">Офіційний сайт</string>\n\t<string name=\"about_feedback_title\">Відгук</string>\n\t<string name=\"about_feedback_hint\">Вкажіть модель телефону, версію Android, плагін Xposed і версію у відповідній програмі, а потім опишіть (як можна більш детально) проблему, яку ви відчуваєте, в іншому випадку вона вважається недійсною для зворотного зв\\'язку (бо ми не можемо ефективно відтворити і виправити вказану проблему тільки  з  \\\"додаток здурів\\\" ;) )</string>\n\t<string name=\"settings_plugin_recommend\">Рекомендований модуль Xposed</string>\n\t<string name=\"advance_settings_disable_resident_notification\">Відключити повідомлення резидента</string>\n\t<string name=\"advance_settings_disable_resident_notification_summary\">Вимкніть резидентное повідомлення VirtualXposed. (Якщо відключено, VirtualXposed може бути часто знищений системою. Будьте обережні!)</string>\n\t<string name=\"settings_module_manage\">Керування модулем Xposed</string>\n\t<string name=\"settings_module_manage_summary\">Включити/Відключити модуль Xposed (ви повинні включити його вручну, щоб він вступив в силу)</string>\n\t<string name=\"xposed_installer_not_found\">Інсталятор Xposed, не знайдений, спочатку додайте його в VirtualXposed!</string>\n\t<string name=\"advance_settings_allow_fake_signature_summary\">Коли включено, ви можете встановити apk, у якого немає підпису (зазвичай використовується в взломаних apk, будьте обережні)</string>\n\t<string name=\"advance_settings_allow_fake_signature\">Дозволити установку apk без підпису.</string>\n\t<string name=\"permission_tip_title\">Важливі поради:</string>\n    <string name=\"permission_tips_content\">%1$s  не підтримує дозвіл на виконання, ви повинні дати заздалегідь необхідні дозволи, будь ласка, надайте всі дозволи, який він вимагатиме на наступному кроці, інакше він може не працювати належним чином.</string>\n    <string name=\"permission_tips_confirm\">Добре, я знаю.</string>\n    <string name=\"permission_denied_tips_content\">Додаток: %1$s не надає необхідного дозволу, якщо він не працює належним чином, перейдіть до управління дозволами свого пристрою та надайте йому дозволи.</string>\n    <string name=\"list_app_access_external_storage\">Якщо ви хочете встановити apk з зовнішнього сховища, дайте дозвіл VirtualXposed.</string>\n    <string name=\"install_gms_title\" >Встановити Google Services</string>\n    <string name=\"install_gms_content\">Сервіси Google підтримується microG, VirtualXposed збирається завантажити якийсь файл (2М), і він може витрачати заряд вашого акумулятора, ви хочете його встановити?</string>\n    <string name=\"install_gms_fail_title\">Помилка встановлення</string>\n    <string name=\"install_gms_fail_content\">Автоматичне встановлення сервісів Google не вдалася, їх також можна встановити вручну.</string>\n    <string name=\"install_gms_fail_ok\">Встановлення вручну</string>\n    <string name=\"uninstall_gms_title\">Видалити Google Services</string>\n    <string name=\"uninstall_gms_content\">Ви хочете видалити сервіси Google? Ви можете їх встановити пізніше.</string>\n    <string name=\"uninstall_gms_ok\">Видалити, підтвердити</string>\n    <string name=\"install_gms_alreay_installed\">Сервіси Google встановлені.</string>\n    <string name=\"install_gms_success\">Google Services успішно встановлені!</string>\n    <string name=\"uninstall_gms_success\">Google Services були успішно видалені!</string>\n    <string name=\"donate_choose_title\">Спосіб пожертвування</string>\n    <string name=\"donate_bitconins_tips\">Мою біткойн-адресу було скопійовано у буфер обміну:)</string>\n    <string name=\"advance_settings_disable_xposed_summary\">Коли відключений, все Xposed модулі не працюватимуть.</string>\n    <string name=\"advance_settings_disable_xposed\">Відключити Xposed</string>\n    <string name=\"prepare_xposed_installer\">Підготовка середовища Xposed, будь ласка, зачекайте…</string>\n    <string name=\"settings_file_manage_text\">Файловий менеджер</string>\n    <string name=\"install_file_manager_tips\">Файловий менеджер підтримується Amaze File Manager, завантажити (близько 3МБ) і встановити зараз?</string>\n    <string name=\"settings_permission_manage_text\">Керування дозволами</string>\n    <string name=\"install_permission_manager_tips\">Керування дозволами реалізовано XPrivacyLua, скачати (близько 1.7МБ) і встановити зараз?</string>\n    <string name=\"exp_tips\">Давно я розкрив інформацію про EXposed.  Після періоду зворотного зв\\'язку та коригування, EXposed досягли важливої ​​віхи.  Багато користувачів можуть цього не знати, дозвольте сьогодні представити вам. \\n\\n\n\nVirtualXposed, який я створив раніше, EXposed - це також додаток, який дозволяє вам використовувати модуль Xposed без root, розблокованого завантажувача.  вони мають і свої переваги, і EXposed буде набагато кращим з точки зору продуктивності та стабільності завдяки роботі безпосередньо в рідній системі;  тоді як VirtualXposed базується на VitualApp, який схожий на Parallel Space.  EXposed народився місяць назад, і його стабільність перевершила VirtualXposed, який розроблявся майже рік. \\n\\n\n\nВ даний час EXposed розміщений в магазині додатків і перейменований в Tai Chi.  Ви можете спробувати :)</string>\n    <string name=\"advance_settings_enable_launcher_summary\">Коли включений, Ви можете вибрати VirtualXposed як лаунчер за замовчуванням для системи</string>\n    <string name=\"advance_settings_enable_launcher\">Увімкнути лаунчер</string>\n    <string name=\"exp_introduce_title\">Простий спосіб використання Xposed</string>\n    <string name=\"exp_introduce_install\">Спробуйте</string>\n    <string name=\"what_is_exp\">Що таке TaiChi?</string>\n    <string name=\"install_choose_way\">Виберіть спосіб встановлення</string>\n    <string name=\"install_choose_content\" >Ви можете використовувати модулі Xposed через TaiChi, за винятком VirtualXposed.  VirtualXposed підтримує Virtual-App, а TaiChi набагато стабільніший.</string>\n    <string name=\"install_choose_taichi\">TaiChi</string>\n    <string name=\"install_taichi_not_exist\">TaiChi не встановлений!</string>\n    <string name=\"install_go_to_install_exp\">Перейти до встановлення TaiChi</string>\n    <string name=\"install_taichi_while_old_version\">Встановлена версія TaiChi застаріла, Встановіть останню версію Taichi!</string>\n    <string name=\"install_go_latest_exp\">Встановити останню версію TaiChi</string>\n    <string name=\"install_complete_and_open\">Відкрити</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-zh-rCN/strings.xml",
    "content": "<resources>\n    <!--<string name=\"app_name\">VirtualApp</string>-->\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"desktop\">桌面</string>\n    <string name=\"add_app\">添加应用</string>\n    <string name=\"preparing\">正在打开App，请稍等…</string>\n    <string name=\"delete\">删除</string>\n    <string name=\"create_shortcut\">创建快捷方式</string>\n    <string name=\"new_user\">新的用户</string>\n    <string name=\"enable\">开启</string>\n    <string name=\"save\">保存</string>\n    <string name=\"save_success\">保存成功!</string>\n    <string name=\"manufacturer\">制造商</string>\n    <string name=\"wait\">请稍后…</string>\n    <string name=\"brand\">品牌</string>\n    <string name=\"device\">机型</string>\n    <string name=\"fake_device_info\">伪造设备信息</string>\n    <string name=\"wifi_status\">Wifi状态</string>\n    <string name=\"config_device_info\">配置设备信息</string>\n    <string name=\"about\">关于</string>\n    <string name=\"clone_apps\">克隆App</string>\n    <string name=\"external_storage\">外置存储</string>\n    <string name=\"install_d\">安装 (%d)</string>\n    <string name=\"install_too_much_once_time\">不能一次性安装超过9个App!</string>\n    <string name=\"versionchecklib_confirm\">立即更新</string>\n    <string name=\"versionchecklib_cancel\">取消</string>\n    <string name=\"menu_virtual_location\">虚拟定位</string>\n    <string name=\"menu_about\">关于</string>\n    <string name=\"menu_reboot\">重启</string>\n    <string name=\"installing_tips\">正在安装 %1$s…</string>\n    <string name=\"update_success_tips\">%1$s 更新成功！</string>\n    <string name=\"install_success_tips\">模块安装完后需要去XposedInstaller的模块设置里勾选才能生效哦～</string>\n    <string name=\"install_fail_tips\">%1$s 安装失败，错误码： %2$s</string>\n    <string name=\"about_page_description\">VirtualXposed是一个基于VirtualApp的，免Root、免解锁BL、免刷机使用Xposed框架的APP。</string>\n    <string name=\"about_feedback_qq_title\">内测 QQ 群（点击复制群号）</string>\n    <string name=\"about_feedback_wechat_title\">内测微信群（点击复制群号）</string>\n    <string name=\"about_feedback_tips\">群号已经复制到剪切版</string>\n    <string name=\"about_version_title\">版本号: %1$s</string>\n    <string name=\"about_donate_title\">支持我</string>\n    <string name=\"reboot_tips_1\">虽然也许你不太相信，但是VirtualXposed确实重启完成了！</string>\n    <string name=\"reboot_tips_2\">别点了，不骗你，真的重启成功了。</string>\n    <string name=\"reboot_tips_3\">不信是吧，死给你看。。</string>\n    <string name=\"meizu_device_tips_title\">检测到魅族系统：</string>\n    <string name=\"meizu_device_tips_content\">受限于魅族系统的限制，您必须先在系统中安装相应的APP以及Xposed模块，然后再克隆到VirtualXposed中才能正常使用。请首先在安装 XposedInstaller 然后克隆到 VAEposed 中！！</string>\n    <string name=\"prompt_alipay_not_found\">你没有安装支付宝 ~_~</string>\n    <string name=\"donate_dialog_title\">关于打赏</string>\n    <string name=\"donate_dialog_content\">维护 VirtualXposed 花费了我很多业余时间，如果它给您带来了便利，可以赞助我一波 :)</string>\n    <string name=\"donate_dialog_yes\">我就要打赏</string>\n    <string name=\"donate_dialog_no\">去github点赞</string>\n    <string name=\"large_app_install_tips\">安装大型APP可能需要花费较长的时间，请耐心等待~</string>\n    <string name=\"about_icon_title\">关于图标</string>\n    <string name=\"about_icon_content\">如果你不喜欢这个图标，赶紧为VirtualXposed设计一个吧！哈哈哈哈哈，我知道你们这些设计师肯定会看不下去的，啊哈哈哈</string>\n    <string name=\"about_icon_yes\">我知道了</string>\n    <string name=\"create_shortcut_success\">创建快捷方式成功！</string>\n    <string name=\"about_thanks\">致谢</string>\n    <string name=\"thanks_dialog_title\">特别鸣谢</string>\n    <string name=\"thanks_dialog_content\">感谢 Cheney 提供超赞的Icon，另外谢谢芑芮、佩奇、以及另外一些我还不知道名字的设计师的辛勤付出；谢谢各位小伙伴提供的创意和建议，特别感谢 YingLin 不厌其烦地帮我实现我的稀烂设计 :)</string>\n    <string name=\"alert_for_doze_mode_title\">关于后台运行</string>\n    <string name=\"alert_for_doze_mode_content\">为了让VirtualXposed内部运行的应用不会频繁被系统杀死，请允许把VirtualXposed加入电池优化白名单；同时，VirtualXposed会尽量保证APP不滥用此权限。请在接下来的系统弹窗中选择\"允许\" :)</string>\n    <string name=\"alert_for_doze_mode_yes\">朕同意了</string>\n    <string name=\"alert_for_doze_mode_no\">我拒绝</string>\n    <string name=\"about_faq_title\">常见问题</string>\n    <string name=\"clear_app\">清除\\n数据</string>\n    <string name=\"stop_app\">强制\\n停止</string>\n    <string name=\"home_menu_delete_title\">删除应用</string>\n    <string name=\"home_menu_delete_content\">是否要从 VirtualXposed 删除 %1$s ?</string>\n    <string name=\"home_menu_clear_title\">清除数据</string>\n    <string name=\"home_menu_clear_content\">确定要删除 %1$s 的数据吗？</string>\n    <string name=\"home_menu_kill_title\">强制停止</string>\n    <string name=\"home_menu_kill_content\">是否要强制停止 %1$s 的运行？</string>\n    <string name=\"add_app_loading_tips\">正在解析安装包 %1$s</string>\n    <string name=\"add_app_installing_tips\">正在安装 %1$s </string>\n    <string name=\"add_app_loading_complete\">%1$s 安装成功！</string>\n    <string name=\"list_app_activity_install\">添加到VirtualXposed</string>\n    <string name=\"settings_about_text\">关于</string>\n    <string name=\"settings_task_manage_text\">任务管理</string>\n    <string name=\"settings_app_manage_text\">应用管理</string>\n    <string name=\"settings_desktop_text\">桌面设置</string>\n    <string name=\"app_manage_uninstall\">卸载</string>\n    <string name=\"app_manage_repair\">尝试修复</string>\n    <string name=\"settings_title\">设置</string>\n    <string name=\"task_manage_uninstall\">结束任务</string>\n    <string name=\"settings_reboot_title\">重启 VirtualXposed</string>\n    <string name=\"settings_reboot_content\">这将使所有运行在 VirtualXposed 内部的APP重启，确认要这么做吗？</string>\n    <string name=\"check_update\">检查更新</string>\n    <string name=\"version_is_latest\">当前版本已是最新！</string>\n    <string name=\"new_version_detected\">检测到新版本：</string>\n    <string name=\"multi_version_tip_title\">安装提示</string>\n    <string name=\"multi_version_tips_content\">你选择了一个已经安装了的应用，是安装一个分身还是覆盖已经安装的版本？\\n\\n已经安装的版本：%1$s\\n即将安装的版本：%2$s</string>\n    <string name=\"multi_version_multi\">安装分身</string>\n    <string name=\"multi_version_cover\">覆盖已有版本</string>\n    <string name=\"multi_version_upgrade\">升级安装</string>\n    <string name=\"multi_version_downgrade\">降级安装</string>\n    <string name=\"app_manage_repair_failed_tips\">很抱歉，修复失败了 :( 请尝试重新安装…</string>\n    <string name=\"app_manage_repairing\">正在修复，请耐心等待…</string>\n    <string name=\"app_manage_repair_success_title\">修复提示</string>\n    <string name=\"app_manage_repair_success_content\">修复成功，请立即重启 VirtualXposed 以保证修复生效。</string>\n    <string name=\"app_manage_repair_reboot_now\">立即重启</string>\n    <string name=\"wallpaper_too_big_tips\">壁纸图片过大，严重拖慢启动速度，建议更换或者恢复默认壁纸~</string>\n    <string name=\"create_shortcut_already_exist\">这个快捷方式已经创建过啦～</string>\n    <string name=\"start_app_failed\">打开应用 %1$s 失败 :(</string>\n    <string name=\"app_manage_redirect_on\">打开存储重定向</string>\n    <string name=\"app_manage_redirect_off\">关闭存储重定向</string>\n    <string name=\"app_manage_redirect_desc\">存储重定向会把应用对真实SD卡的访问重定向到虚拟的SD卡中，可以防止某些APP在你的SD中乱创建目录；但是，开启存储重定向之后，应用无法再访问真实的SD卡，请按需选择。</string>\n    <string name=\"app_manage_redirect_on_confirm\">确认打开</string>\n    <string name=\"app_manage_redirect_off_confirm\">确认关闭</string>\n    <string name=\"shared_to_vxp\">分享到VXP内的应用</string>\n    <string name=\"shared_to_vxp_failed\">分享失败 :( 请稍后重试…</string>\n    <string name=\"app_installer_label\">安装到VirtualXposed</string>\n    <string name=\"install_complete\">完成</string>\n    <string name=\"install_fail\">安装失败：%1$s</string>\n    <string name=\"install\">安装</string>\n    <string name=\"install_package\">添加新应用 : %s</string>\n    <string name=\"install_package_version_tips\">你选择了一个已经安装了的应用，\\n\\n已经安装的版本：%1$s\\n即将安装的版本：%2$s，确认安装？</string>\n    <string name=\"settings_add_app_summary\">必须先把应用以及Xposed模块都添加到 VirtualXposed ，否则Xposed模块不会生效。</string>\n    <string name=\"settings_advance\">高级设置</string>\n    <string name=\"advance_settings_hide_settings\">隐藏桌面的设置按钮</string>\n    <string name=\"advance_settings_disable_installer\">禁用 VirtualXposed 的APK安装器</string>\n    <string name=\"advance_settings_hide_settings_summary\">如果你可以在主界面通过菜单键（长按多任务或者虚拟菜单键）进入设置，那么可以隐藏这个按钮；否则你将无法进入设置！！\\n(强制停止VirtualXposed后生效）</string>\n    <string name=\"advance_settings_disable_installer_summary\">在系统中安装APK文件的时候，不显示VirtualXposed的安装器</string>\n    <string name=\"advance_settings_directly_back\">直接返回</string>\n    <string name=\"advance_settings_directly_back_summary\">内部APP退出时，直接返回到系统桌面而不是VirtualXposed的虚拟桌面(强制停止VirtualXposed后生效）</string>\n    <string name=\"install_self_eggs\">小伙子，你这个想法很有前途 :)</string>\n    <string name=\"advance_settings_install_gms\">安装/移除Google服务</string>\n    <string name=\"about_feedback_tel_title\">Telegram 群组: %1$s</string>\n    <string name=\"advance_settings_copy_file\">内部文件复制</string>\n    <string name=\"about_website_title\">官网（使用教程/历史版本下载/模块下载)</string>\n    <string name=\"about_feedback_title\">问题反馈</string>\n    <string name=\"about_feedback_hint\">请说明你的机型，系统版本，使用的Xposed插件以及对应APP版本，然后尽可能详细地描述你遇到的问题；否则视为无效反馈。\\n</string>\n    <string name=\"settings_plugin_recommend\">常用模块</string>\n    <string name=\"advance_settings_disable_resident_notification\">关闭常驻通知栏</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">关闭常驻通知栏之后，VirtualXposed有可能极易被系统杀死，导致无法收到消息等问题；如果你能确保 VirtualXposed 不会被杀死，可以尝试。总之，慎重操作！（重启VirtualXposed后生效）</string>\n    <string name=\"settings_module_manage\">模块管理</string>\n    <string name=\"settings_module_manage_summary\">开启或者关闭Xposed模块（Xposed模块安装之后必须手动开启才能生效）</string>\n    <string name=\"xposed_installer_not_found\">没有找到 Xposed Installer, 请先把它添加到 VirtualXposed 中！</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">启用之后，您可以安装没有签名的APK到 VirtualXposed （通常用于破解版的APP，请注意安全。如果APP有签名校检，依然会无法使用）</string>\n    <string name=\"advance_settings_allow_fake_signature\">允许安装没有签名的应用</string>\n    <string name=\"permission_tip_title\">重要提示：</string>\n    <string name=\"permission_tips_content\">%1$s 不支持动态申请权限, 您必须提前赋予它需要的所有必要权限, 请在它接下来的权限请求中全部选择允许，否则他可能无法正常运行。</string>\n    <string name=\"permission_tips_confirm\">我知道了</string>\n    <string name=\"permission_denied_tips_content\">%1$s 不支持动态申请权限，如果它工作不正常，请去您设备的系统权限管理中赋予 VirtualXposed 必要权限。</string>\n    <string name=\"list_app_access_external_storage\">如果你想把SD中的APK安装到 VirtualXposed，请赋予它外部存储权限。</string>\n    <string name=\"install_gms_title\">安装Google服务</string>\n    <string name=\"install_gms_content\">Google 服务是通过 microG 支持的，需要下载 2M 左右的文件，安装完之后耗电量可能会增加，确认需要安装吗？</string>\n    <string name=\"install_gms_fail_title\">安装失败</string>\n    <string name=\"install_gms_fail_content\">自动安装Google 服务失败，你可以参考教程手动安装。</string>\n    <string name=\"install_gms_fail_ok\">查看教程</string>\n    <string name=\"uninstall_gms_title\">移除Google服务</string>\n    <string name=\"uninstall_gms_content\">确定要移除 Google 服务吗？需要的时候你可以重新安装它。</string>\n    <string name=\"uninstall_gms_ok\">确认移除</string>\n    <string name=\"install_gms_success\">Google 服务已经安装成功！！</string>\n    <string name=\"uninstall_gms_success\">Google服务已经移除成功！！</string>\n    <string name=\"donate_choose_title\">选择打赏方式</string>\n    <string name=\"donate_bitconins_tips\">我的比特币地址已经复制到剪切板 :)</string>\n    <string name=\"donate_alipay\">支付宝</string>\n    <string name=\"advance_settings_disable_xposed\">关闭 Xposed</string>\n    <string name=\"advance_settings_disable_xposed_summary\">关闭Xposed之后，所有的Xposed均不会生效。</string>\n    <string name=\"prepare_xposed_installer\">正在准备 Xposed 环境，请等待…</string>\n    <string name=\"install_file_manager_tips\">文件管理是通过 Amaze File Manager 支持的，是否立即下载（约3M）并安装？</string>\n    <string name=\"settings_permission_manage_text\">权限管理</string>\n    <string name=\"settings_file_manage_text\">文件管理</string>\n    <string name=\"install_permission_manager_tips\">权限管理是通过 XPrivacyLua 实现的，是否立即下载（约2M）并安装？</string>\n    <string name=\"advance_settings_enable_launcher_summary\">开启之后，可以设置 VirtualXposed 作为系统桌面（重启 VirtualXposed 生效）</string>\n    <string name=\"advance_settings_enable_launcher\">启用桌面功能</string>\n    <string name=\"exp_introduce_title\">另一种免Root用Xposed的方式</string>\n    <string name=\"exp_introduce_install\">去看看</string>\n    <string name=\"what_is_exp\">太极是什么？</string>\n    <string name=\"install_choose_way\">选择安装方式</string>\n    <string name=\"install_choose_content\" >除了 VirtualXposed 之外，您还可以通过 太极 来实现免Root使用 Xposed 模块。VirtualXposed 支持多开，太极则更加稳定。</string>\n    <string name=\"install_choose_taichi\">太极</string>\n    <string name=\"install_taichi_not_exist\">您没有安装 太极</string>\n    <string name=\"install_go_to_install_exp\">去安装太极</string>\n    <string name=\"install_taichi_while_old_version\">你安装的 太极 版本过低，请使用新版本的太极！</string>\n    <string name=\"install_go_latest_exp\">去安装新版太极</string>\n    <string name=\"install_complete_and_open\">打开</string>\n    <string name=\"unsupported_for_32bit_app\">不支持 32 位的应用！</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/values-zh-rTW/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">VirtualXposed</string>\n    <string name=\"desktop\">桌面</string>\n    <string name=\"add_app\">新增程式</string>\n    <string name=\"preparing\">正在打開App，請稍等…</string>\n    <string name=\"delete\">刪除</string>\n    <string name=\"create_shortcut\">建立捷徑</string>\n    <string name=\"new_user\">新的使用者</string>\n    <string name=\"enable\">開啟</string>\n    <string name=\"save\">儲存</string>\n    <string name=\"save_success\">儲存成功!</string>\n    <string name=\"manufacturer\">製造商</string>\n    <string name=\"wait\">請稍後…</string>\n    <string name=\"brand\">品牌</string>\n    <string name=\"device\">機型</string>\n    <string name=\"fake_device_info\">偽造設備訊息</string>\n    <string name=\"wifi_status\">Wifi狀態</string>\n    <string name=\"config_device_info\">設定設備訊息</string>\n    <string name=\"about\">關於</string>\n    <string name=\"clone_apps\">複製App</string>\n    <string name=\"external_storage\">外部儲存</string>\n    <string name=\"install_d\">安裝 (%d)</string>\n    <string name=\"install_too_much_once_time\">不能一次性安裝超過9個App!</string>\n    <string name=\"versionchecklib_confirm\">立即更新</string>\n    <string name=\"versionchecklib_cancel\">取消</string>\n    <string name=\"menu_virtual_location\">虛擬定位</string>\n    <string name=\"menu_about\">關於</string>\n    <string name=\"menu_reboot\">重啟</string>\n    <string name=\"installing_tips\">正在安裝 %1$s…</string>\n    <string name=\"update_success_tips\">%1$s 更新成功！</string>\n    <string name=\"install_success_tips\">模組安裝完後需要去XposedInstaller的模組設定裡勾選才能生效哦～</string>\n    <string name=\"install_fail_tips\">%1$s 安裝失敗，錯誤碼： %2$s</string>\n    <string name=\"about_page_description\">VirtualXposed是一個基於VirtualApp的，免Root、免解鎖BL、免刷機使用Xposed框架的APP。</string>\n    <string name=\"about_feedback_qq_title\">內測 QQ 群（輕觸複製群號）</string>\n    <string name=\"about_feedback_wechat_title\">內測微信群（輕觸複製群號）</string>\n    <string name=\"about_feedback_tips\">群號已經複製到剪貼簿</string>\n    <string name=\"about_version_title\">版本號: %1$s</string>\n    <string name=\"about_donate_title\">支持我</string>\n    <string name=\"reboot_tips_1\">雖然也許你不太相信，但是VirtualXposed確實重啟完成了！</string>\n    <string name=\"reboot_tips_2\">別點了，不騙你，真的重啟成功了。</string>\n    <string name=\"reboot_tips_3\">不信是吧，死給你看。。</string>\n    <string name=\"meizu_device_tips_title\">檢測到魅族系統：</string>\n    <string name=\"meizu_device_tips_content\">受限於魅族系統的限制，您必須先在系統中安裝相應的APP以及Xposed模組，然後再複製到VirtualXposed中才能正常使用。請首先在安裝 XposedInstaller 然後複製到 VAEposed 中！！</string>\n    <string name=\"prompt_alipay_not_found\">你沒有安裝支付寶 ~_~</string>\n    <string name=\"donate_dialog_title\">關於打賞</string>\n    <string name=\"donate_dialog_content\">維護 VirtualXposed 花費了我很多業餘時間，如果它給您帶來了便利，可以贊助我一波 :)</string>\n    <string name=\"donate_dialog_yes\">我就要打賞</string>\n    <string name=\"donate_dialog_no\">去github按讚</string>\n    <string name=\"large_app_install_tips\">安裝大型APP可能需要花費較長的時間，請耐心等待~</string>\n    <string name=\"about_icon_title\">關於圖示</string>\n    <string name=\"about_icon_content\">如果你不喜歡這個圖示，趕緊為VirtualXposed設計一個吧！哈哈哈哈哈，我知道你們這些設計師肯定會看不下去的，啊哈哈哈</string>\n    <string name=\"about_icon_yes\">我知道了</string>\n    <string name=\"create_shortcut_success\">建立捷徑成功！</string>\n    <string name=\"about_thanks\">致謝</string>\n    <string name=\"thanks_dialog_title\">特別鳴謝</string>\n    <string name=\"thanks_dialog_content\">感謝 Cheney 提供超讚的Icon，另外謝謝芑芮、佩奇、以及另外一些我還不知道名字的設計師的辛勤付出；謝謝各位小伙伴提供的創意和建議，特別感謝 YingLin 不厭其煩地幫我實現我的稀爛設計 :)</string>\n    <string name=\"alert_for_doze_mode_title\">關於後台執行</string>\n    <string name=\"alert_for_doze_mode_content\">為了讓VirtualXposed內部執行的程式不會頻繁被系統殺死，請允許把VirtualXposed加入電池最佳化白名單；同時，VirtualXposed會儘量保證APP不濫用此權限。請在接下來的系統跳出視窗中選擇\"允許\" :)</string>\n    <string name=\"alert_for_doze_mode_yes\">朕同意了</string>\n    <string name=\"alert_for_doze_mode_no\">我拒絕</string>\n    <string name=\"about_faq_title\">常見問題</string>\n    <string name=\"clear_app\">清除\\n資料</string>\n    <string name=\"stop_app\">強制\\n停止</string>\n    <string name=\"home_menu_delete_title\">刪除程式</string>\n    <string name=\"home_menu_delete_content\">是否要從 VirtualXposed 刪除 %1$s ?</string>\n    <string name=\"home_menu_clear_title\">清除資料</string>\n    <string name=\"home_menu_clear_content\">確定要刪除 %1$s 的資料嗎？</string>\n    <string name=\"home_menu_kill_title\">強制停止</string>\n    <string name=\"home_menu_kill_content\">是否要強制停止 %1$s 的執行？</string>\n    <string name=\"add_app_loading_tips\">正在解析安裝包 %1$s</string>\n    <string name=\"add_app_installing_tips\">正在安裝 %1$s </string>\n    <string name=\"add_app_loading_complete\">%1$s 安裝成功！</string>\n    <string name=\"list_app_activity_install\">新增到VirtualXposed</string>\n    <string name=\"settings_about_text\">關於</string>\n    <string name=\"settings_task_manage_text\">任務管理</string>\n    <string name=\"settings_app_manage_text\">程式管理</string>\n    <string name=\"settings_desktop_text\">桌面設定</string>\n    <string name=\"app_manage_uninstall\">移除</string>\n    <string name=\"app_manage_repair\">嘗試修復</string>\n    <string name=\"settings_title\">設定</string>\n    <string name=\"task_manage_uninstall\">結束任務</string>\n    <string name=\"settings_reboot_title\">重啟 VirtualXposed</string>\n    <string name=\"settings_reboot_content\">這將使所有執行在 VirtualXposed 內部的APP重啟，確認要這麼做嗎？</string>\n    <string name=\"check_update\">檢查更新</string>\n    <string name=\"version_is_latest\">目前版本已是最新！</string>\n    <string name=\"new_version_detected\">檢測到新版本：</string>\n    <string name=\"multi_version_tip_title\">安裝提示</string>\n    <string name=\"multi_version_tips_content\">你選擇了一個已經安裝了的程式，是安裝一個分身還是覆蓋已經安裝的版本？\\n\\n已經安裝的版本：%1$s\\n即將安裝的版本：%2$s</string>\n    <string name=\"multi_version_multi\">安裝分身</string>\n    <string name=\"multi_version_cover\">覆蓋已有版本</string>\n    <string name=\"multi_version_upgrade\">升級安裝</string>\n    <string name=\"multi_version_downgrade\">降級安裝</string>\n    <string name=\"app_manage_repair_failed_tips\">很抱歉，修復失敗了 :( 請嘗試重新安裝…</string>\n    <string name=\"app_manage_repairing\">正在修復，請耐心等待…</string>\n    <string name=\"app_manage_repair_success_title\">修復提示</string>\n    <string name=\"app_manage_repair_success_content\">修復成功，請立即重啟 VirtualXposed 以保證修復生效。</string>\n    <string name=\"app_manage_repair_reboot_now\">立即重啟</string>\n    <string name=\"wallpaper_too_big_tips\">壁紙圖片過大，嚴重拖慢啟動速度，建議更換或者恢復預設壁紙~</string>\n    <string name=\"create_shortcut_already_exist\">這個捷徑已經建立過啦～</string>\n    <string name=\"start_app_failed\">打開程式 %1$s 失敗 :(</string>\n    <string name=\"app_manage_redirect_on\">打開儲存重定向</string>\n    <string name=\"app_manage_redirect_off\">關閉儲存重定向</string>\n    <string name=\"app_manage_redirect_desc\">儲存重定向會把程式對真實SD卡的訪問重定向到虛擬的SD卡中，可以防止某些APP在你的SD中亂建立目錄；但是，開啟儲存重定向之後，程式無法再訪問真實的SD卡，請按需選擇。</string>\n    <string name=\"app_manage_redirect_on_confirm\">確認打開</string>\n    <string name=\"app_manage_redirect_off_confirm\">確認關閉</string>\n    <string name=\"shared_to_vxp\">分享到VXP內的程式</string>\n    <string name=\"shared_to_vxp_failed\">分享失敗 :( 請稍後重試…</string>\n    <string name=\"app_installer_label\">安裝到VirtualXposed</string>\n    <string name=\"install_complete\">完成</string>\n    <string name=\"install_fail\">安裝失敗：%1$s</string>\n    <string name=\"install\">安裝</string>\n    <string name=\"install_package\">安裝新程式 : %s</string>\n    <string name=\"install_package_version_tips\">你選擇了一個已經安裝了的程式，\\n\\n已經安裝的版本：%1$s\\n即將安裝的版本：%2$s，確認安裝？</string>\n    <string name=\"settings_add_app_summary\">必須先把程式以及Xposed模組都新增到 VirtualXposed ，否則Xposed模組不會生效。</string>\n    <string name=\"settings_advance\">進階設定</string>\n    <string name=\"advance_settings_hide_settings\">隱藏桌面的設定按鈕</string>\n    <string name=\"advance_settings_disable_installer\">禁用 VirtualXposed 的APK安裝器</string>\n    <string name=\"advance_settings_hide_settings_summary\">如果你可以在主介面透過選單鍵（長按多任務或者虛擬選單鍵）進入設定，那麼可以隱藏這個按鈕；否則你將無法進入設定！！\\n(強制停止VirtualXposed後生效）</string>\n    <string name=\"advance_settings_disable_installer_summary\">在系統中安裝APK檔案的時候，不顯示VirtualXposed的安裝器</string>\n    <string name=\"advance_settings_directly_back\">直接返回</string>\n    <string name=\"advance_settings_directly_back_summary\">內部APP退出時，直接返回到系統桌面而不是VirtualXposed的虛擬桌面(強制停止VirtualXposed後生效）</string>\n    <string name=\"install_self_eggs\">小伙子，你這個想法很有前途 :)</string>\n    <string name=\"advance_settings_install_gms\">安裝/移除Google服務</string>\n    <string name=\"about_feedback_tel_title\">Telegram 群組: %1$s</string>\n    <string name=\"advance_settings_copy_file\">內部檔案複製</string>\n    <string name=\"about_website_title\">官網（使用教學/歷史版本下載/模組下載)</string>\n    <string name=\"about_feedback_title\">問題回饋</string>\n    <string name=\"about_feedback_hint\">請說明你的機型，系統版本，使用的Xposed插件以及對應APP版本，然後儘可能詳細地描述你遇到的問題；否則視為無效回饋。\\n</string>\n    <string name=\"settings_plugin_recommend\">常用模組</string>\n    <string name=\"advance_settings_disable_resident_notification\">關閉常駐通知欄</string>\n    <string name=\"advance_settings_disable_resident_notification_summary\">關閉常駐通知欄之後，VirtualXposed有可能極易被系統殺死，導致無法收到消息等問題；如果你能確保 VirtualXposed 不會被殺死，可以嘗試。總之，慎重操作！（重啟VirtualXposed後生效）</string>\n    <string name=\"settings_module_manage\">模組管理</string>\n    <string name=\"settings_module_manage_summary\">開啟或者關閉Xposed模組（Xposed模組安裝之後必須手動開啟才能生效）</string>\n    <string name=\"xposed_installer_not_found\">沒有找到 Xposed Installer, 請先把它新增到 VirtualXposed 中！</string>\n    <string name=\"advance_settings_allow_fake_signature_summary\">啟用之後，您可以安裝沒有簽名的APK到 VirtualXposed （通常用於破解版的APP，請注意安全。如果APP有簽名校檢，依然會無法使用）</string>\n    <string name=\"advance_settings_allow_fake_signature\">允許安裝沒有簽名的程式</string>\n    <string name=\"permission_tip_title\">重要提示：</string>\n    <string name=\"permission_tips_content\">%1$s 不支援動態申請權限, 您必須提前賦予它需要的所有必要權限, 請在它接下來的權限請求中全部選擇允許，否則它將無法執行。</string>\n    <string name=\"permission_tips_confirm\">我知道了</string>\n    <string name=\"permission_denied_tips_content\">%1$s 不支持動態申請權限，如果它工作不正常，請去您設備的系統權限管理中賦予 VirtualXposed 必要權限。</string>\n    <string name=\"list_app_access_external_storage\">如果你想把SD中的APK安裝到 VirtualXposed，請賦予它外部儲存權限。</string>\n    <string name=\"install_gms_title\">安裝Google服務</string>\n    <string name=\"install_gms_content\">Google 服務是透過 microG 支援的，需要下載 2M 左右的檔案，安裝完之後耗電量可能會增加，確認需要安裝嗎？</string>\n    <string name=\"install_gms_fail_title\">安裝失敗</string>\n    <string name=\"install_gms_fail_content\">自動安裝Google 服務失敗，你可以參考教學手動安裝。</string>\n    <string name=\"install_gms_fail_ok\">查看教學</string>\n    <string name=\"uninstall_gms_title\">移除Google服務</string>\n    <string name=\"uninstall_gms_content\">確定要移除 Google 服務嗎？需要的時候你可以重新安裝它。</string>\n    <string name=\"uninstall_gms_ok\">確認移除</string>\n    <string name=\"install_gms_success\">Google 服務已經安裝成功！！</string>\n    <string name=\"uninstall_gms_success\">Google服務已經移除成功！！</string>\n    <string name=\"donate_choose_title\">選擇打賞方式</string>\n    <string name=\"donate_bitconins_tips\">我的比特幣地址已經複製到剪貼簿 :)</string>\n    <string name=\"donate_alipay\">支付寶</string>\n    <string name=\"advance_settings_disable_xposed\">關閉 Xposed</string>\n    <string name=\"advance_settings_disable_xposed_summary\">關閉Xposed之後，所有的Xposed均不會生效。</string>\n    <string name=\"prepare_xposed_installer\">正在準備 Xposed 環境，請等待…</string>\n    <string name=\"settings_file_manage_text\">文件管理</string>\n    <string name=\"install_file_manager_tips\">文件管理是通過 Amaze File Manager 支持的，是否立即下載（約3M）並安裝？</string>\n    <string name=\"settings_permission_manage_text\">權限管理</string>\n    <string name=\"install_permission_manager_tips\">權限管理由XPrivacyLua實現，下載（約1.7M）並立即安裝？</string>\n    <string name=\"advance_settings_enable_launcher_summary\">Enable Launcher</string>\n    <string name=\"advance_settings_enable_launcher\">Enable Launcher</string>\n    <string name=\"install_complete_and_open\">打開</string>\n    <string name=\"unsupported_for_32bit_app\">不支持 32 位的應用！</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/app/src/main/res/xml/settings_preferences.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <Preference\n        android:key=\"settings_add_app\"\n        android:persistent=\"false\"\n        android:summary=\"@string/settings_add_app_summary\"\n        android:title=\"@string/add_app\" />\n\n    <Preference\n        android:key=\"settings_module_manage\"\n        android:persistent=\"false\"\n        android:summary=\"@string/settings_module_manage_summary\"\n        android:title=\"@string/settings_module_manage\" />\n\n    <Preference\n        android:key=\"settings_plugin_recommend\"\n        android:persistent=\"false\"\n        android:title=\"@string/settings_plugin_recommend\" />\n\n    <PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:key=\"settings_advance\"\n        android:title=\"@string/settings_advance\">\n\n        <Preference\n            android:key=\"advance_settings_install_gms\"\n            android:persistent=\"false\"\n            android:title=\"@string/advance_settings_install_gms\"/>\n\n        <Preference\n            android:key=\"settings_file_manage\"\n            android:persistent=\"false\"\n            android:title=\"@string/settings_file_manage_text\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_disable_xposed\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_disable_xposed_summary\"\n            android:title=\"@string/advance_settings_disable_xposed\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_disable_resident_notification\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_disable_resident_notification_summary\"\n            android:title=\"@string/advance_settings_disable_resident_notification\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_hide_settings\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_hide_settings_summary\"\n            android:title=\"@string/advance_settings_hide_settings\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_allow_fake_signature\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_allow_fake_signature_summary\"\n            android:title=\"@string/advance_settings_allow_fake_signature\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_disable_installer\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_disable_installer_summary\"\n            android:title=\"@string/advance_settings_disable_installer\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_enable_launcher\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_enable_launcher_summary\"\n            android:title=\"@string/advance_settings_enable_launcher\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:key=\"advance_settings_directly_back\"\n            android:persistent=\"true\"\n            android:summary=\"@string/advance_settings_directly_back_summary\"\n            android:title=\"@string/advance_settings_directly_back\" />\n\n        <Preference\n            android:key=\"settings_desktop\"\n            android:persistent=\"false\"\n            android:title=\"@string/settings_desktop_text\" />\n    </PreferenceScreen>\n\n    <Preference\n        android:key=\"settings_permission_manage\"\n        android:persistent=\"false\"\n        android:title=\"@string/settings_permission_manage_text\" />\n\n    <Preference\n        android:key=\"settings_app_manage\"\n        android:persistent=\"false\"\n        android:title=\"@string/settings_app_manage_text\" />\n\n    <Preference\n        android:key=\"settings_task_manage\"\n        android:persistent=\"false\"\n        android:title=\"@string/settings_task_manage_text\" />\n\n    <Preference\n        android:key=\"settings_donate\"\n        android:persistent=\"false\"\n        android:title=\"@string/about_donate_title\" />\n\n    <Preference\n        android:key=\"settings_faq\"\n        android:persistent=\"false\"\n        android:title=\"@string/about_faq_title\" />\n\n    <Preference\n        android:key=\"settings_about\"\n        android:persistent=\"false\"\n        android:title=\"@string/settings_about_text\" />\n\n    <Preference\n        android:key=\"settings_reboot\"\n        android:persistent=\"false\"\n        android:title=\"@string/menu_reboot\" />\n</PreferenceScreen>\n"
  },
  {
    "path": "VirtualApp/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        maven {\n            url 'https://maven.google.com/'\n            name 'Google'\n        }\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.2.1'\n        classpath 'com.android.tools.build:gradle-experimental:0.11.1'\n        // We recommend changing it to the latest version from our changelog:\n        // https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        maven {\n            url \"https://jitpack.io\"\n        }\n        maven {\n            url 'https://maven.google.com/'\n            name 'Google'\n        }\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "VirtualApp/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Oct 29 11:05:44 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.6-all.zip\n"
  },
  {
    "path": "VirtualApp/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useDeprecatedNdk=true"
  },
  {
    "path": "VirtualApp/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "VirtualApp/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "VirtualApp/lib/.gitignore",
    "content": "/build\n.externalNativeBuild/\nobj/\n"
  },
  {
    "path": "VirtualApp/lib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 28\n    buildToolsVersion '28.0.3'\n\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 22\n        versionCode 1\n        versionName \"1.0\"\n        externalNativeBuild {\n            ndkBuild {\n                abiFilters \"arm64-v8a\", \"x86_64\"\n            }\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    externalNativeBuild {\n        ndkBuild {\n            path file(\"src/main/jni/Android.mk\")\n        }\n    }\n    lintOptions {\n        //IJobService need NewApi\n        warning 'NewApi','OnClick'\n        checkReleaseBuilds false\n        // Or, if you prefer, you can continue to check for errors in release builds,\n        // but continue the build even when errors are found:\n        abortOnError false\n    }\n}\n\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    api(\"me.weishu.exposed:exposed-core:0.8.1\") {\n        exclude group: 'me.weishu', module: 'free_reflection'\n        exclude group: 'me.weishu', module: 'epic'\n        exclude group: 'me.weishu.exposed', module: 'exposed-xposedapi'\n    }\n    implementation \"me.weishu:free_reflection:3.0.1\"\n    implementation \"me.weishu:epic:0.11.1\"\n    implementation \"me.weishu.exposed:exposed-xposedapi:0.4.6\"\n}\n\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n"
  },
  {
    "path": "VirtualApp/lib/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/lody/Desktop/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.lody.virtual\">\n\n    <uses-permission android:name=\"com.huawei.authentication.HW_ACCESS_AUTH_SERVICE\" />\n\n    <uses-permission android:name=\"com.samsung.svoice.sync.READ_DATABASE\" />\n    <uses-permission android:name=\"com.samsung.svoice.sync.ACCESS_SERVICE\" />\n    <uses-permission android:name=\"com.samsung.svoice.sync.WRITE_DATABASE\" />\n    <uses-permission android:name=\"com.sec.android.app.voicenote.Controller\" />\n    <uses-permission android:name=\"com.sec.android.permission.VOIP_INTERFACE\" />\n    <uses-permission android:name=\"com.sec.android.permission.LAUNCH_PERSONAL_PAGE_SERVICE\" />\n    <uses-permission android:name=\"com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY\" />\n    <uses-permission android:name=\"com.samsung.android.providers.context.permission.READ_RECORD_AUDIO\" />\n    <uses-permission android:name=\"com.samsung.android.providers.context.permission.WRITE_RECORD_AUDIO\" />\n    <uses-permission android:name=\"com.sec.android.settings.permission.SOFT_RESET\" />\n    <uses-permission android:name=\"sec.android.permission.READ_MSG_PREF\" />\n    <uses-permission android:name=\"com.samsung.android.scloud.backup.lib.read\" />\n    <uses-permission android:name=\"com.samsung.android.scloud.backup.lib.write\" />\n\n    <uses-permission android:name=\"android.permission.BIND_DIRECTORY_SEARCH\" />\n    <uses-permission android:name=\"android.permission.UPDATE_APP_OPS_STATS\" />\n    <uses-permission android:name=\"com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL\" />\n\n    <uses-permission\n        android:name=\"android.permission.ACCOUNT_MANAGER\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <uses-permission\n        android:name=\"android.permission.PACKAGE_USAGE_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.USE_CREDENTIALS\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\" />\n    <uses-permission\n        android:name=\"android.permission.ACCESS_MOCK_LOCATION\"\n        tools:ignore=\"MockLocation\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIMAX_STATE\" />\n    <uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\" />\n    <uses-permission\n        android:name=\"android.permission.BIND_APPWIDGET\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n    <uses-permission android:name=\"android.permission.BODY_SENSORS\" />\n    <uses-permission android:name=\"android.permission.BROADCAST_STICKY\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIFI_MULTICAST_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIMAX_STATE\" />\n    <uses-permission android:name=\"android.permission.CLEAR_APP_CACHE\" />\n    <uses-permission android:name=\"android.permission.DISABLE_KEYGUARD\" />\n    <uses-permission android:name=\"android.permission.DOWNLOAD_WITHOUT_NOTIFICATION\" />\n    <uses-permission android:name=\"android.permission.EXPAND_STATUS_BAR\" />\n    <uses-permission android:name=\"android.permission.FLASHLIGHT\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.GET_CLIPS\" />\n    <uses-permission android:name=\"android.permission.GET_PACKAGE_SIZE\" />\n    <uses-permission android:name=\"android.permission.GET_TASKS\" />\n    <uses-permission android:name=\"android.permission.KILL_BACKGROUND_PROCESSES\" />\n    <uses-permission android:name=\"android.permission.MANAGE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.NFC\" />\n    <uses-permission android:name=\"android.permission.PERSISTENT_ACTIVITY\" />\n    <uses-permission android:name=\"android.permission.PROCESS_OUTGOING_CALLS\" />\n    <uses-permission android:name=\"android.permission.READ_CALENDAR\" />\n    <uses-permission android:name=\"android.permission.READ_CALL_LOG\" />\n    <uses-permission android:name=\"android.permission.READ_CELL_BROADCASTS\" />\n    <uses-permission android:name=\"android.permission.READ_CLIPS\" />\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_INSTALL_SESSIONS\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PROFILE\" />\n    <uses-permission android:name=\"android.permission.READ_SMS\" />\n    <uses-permission android:name=\"android.permission.READ_SOCIAL_STREAM\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_STATS\" />\n    <uses-permission android:name=\"android.permission.READ_USER_DICTIONARY\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_MMS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_SMS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_WAP_PUSH\" />\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.REORDER_TASKS\" />\n    <uses-permission android:name=\"android.permission.RESTART_PACKAGES\" />\n    <uses-permission android:name=\"android.permission.SEND_SMS\" />\n    <uses-permission android:name=\"android.permission.SET_TIME_ZONE\" />\n    <uses-permission android:name=\"android.permission.SET_WALLPAPER\" />\n    <uses-permission android:name=\"android.permission.SET_WALLPAPER_HINTS\" />\n    <uses-permission android:name=\"android.permission.SUBSCRIBED_FEEDS_READ\" />\n    <uses-permission android:name=\"android.permission.SUBSCRIBED_FEEDS_WRITE\" />\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />\n    <uses-permission android:name=\"android.permission.TRANSMIT_IR\" />\n    <uses-permission android:name=\"android.permission.USE_SIP\" />\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.WRITE_CALENDAR\" />\n    <uses-permission android:name=\"android.permission.WRITE_CALL_LOG\" />\n    <uses-permission android:name=\"android.permission.WRITE_CLIPS\" />\n    <uses-permission android:name=\"android.permission.WRITE_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_PROFILE\" />\n    <uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.WRITE_SMS\" />\n    <uses-permission android:name=\"android.permission.WRITE_SOCIAL_STREAM\" />\n    <uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.WRITE_USER_DICTIONARY\" />\n    <uses-permission android:name=\"android.permission.USE_FINGERPRINT\" />\n    <uses-permission android:name=\"com.android.alarm.permission.SET_ALARM\" />\n    <uses-permission android:name=\"com.android.browser.permission.READ_HISTORY_BOOKMARKS\" />\n    <uses-permission android:name=\"com.android.browser.permission.WRITE_HISTORY_BOOKMARKS\" />\n    <uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\" />\n    <uses-permission android:name=\"com.android.launcher.permission.UNINSTALL_SHORTCUT\" />\n    <uses-permission android:name=\"com.android.vending.BILLING\" />\n    <uses-permission android:name=\"com.android.vending.CHECK_LICENSE\" />\n    <uses-permission android:name=\"com.android.voicemail.permission.ADD_VOICEMAIL\" />\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\" />\n    <uses-permission android:name=\"com.google.android.gms.permission.ACTIVITY_RECOGNITION\" />\n    <uses-permission android:name=\"com.google.android.gms.permission.AD_ID_NOTIFICATION\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.OTHER_SERVICES\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.YouTubeUser\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.adsense\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.adwords\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.ah\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.android\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.androidsecure\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.blogger\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.cl\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.cp\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.dodgeball\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.finance\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.gbase\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.grandcentral\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.groups2\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.health\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.ig\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.jotspot\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.knol\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.lh2\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.local\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.mail\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.mobile\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.news\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.notebook\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.orkut\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.print\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.sierra\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.sierraqa\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.sierrasandbox\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.sitemaps\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.speech\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.speechpersonalization\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.talk\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.wifi\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.wise\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.writely\" />\n    <uses-permission android:name=\"com.google.android.googleapps.permission.GOOGLE_AUTH.youtube\" />\n    <uses-permission android:name=\"com.google.android.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.google.android.providers.gsf.permission.READ_GSERVICES\" />\n    <uses-permission android:name=\"com.google.android.providers.talk.permission.READ_ONLY\" />\n    <uses-permission android:name=\"com.google.android.providers.talk.permission.WRITE_ONLY\" />\n    <uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\" />\n    <uses-permission android:name=\"android.permission.READ_LOGS\" />\n    <uses-permission\n        android:name=\"android.permission.INSTALL_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.DELETE_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CLEAR_APP_USER_DATA\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_MEDIA_STORAGE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.ACCESS_CACHE_FILESYSTEM\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.READ_OWNER_DATA\" />\n    <uses-permission android:name=\"android.permission.WRITE_OWNER_DATA\" />\n    <uses-permission android:name=\"android.permission.CHANGE_CONFIGURATION\" />\n    <uses-permission\n        android:name=\"android.permission.DEVICE_POWER\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.BATTERY_STATS\" />\n    <uses-permission android:name=\"android.permission.ACCESS_DOWNLOAD_MANAGER\" />\n    <uses-permission android:name=\"com.android.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.android.launcher.permission.WRITE_SETTINGS\" />\n    <uses-permission android:name=\"com.android.launcher3.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.android.launcher2.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.teslacoilsw.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.actionlauncher.playstore.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.mx.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.anddoes.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.apusapps.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.tsf.shell.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.htc.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.lenovo.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.oppo.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.bbk.launcher2.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.s.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"cn.nubia.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.huawei.android.launcher.permission.READ_SETTINGS\" />\n    <uses-permission android:name=\"com.huawei.android.launcher.permission.CHANGE_BADGE\" />\n    <uses-permission android:name=\"android.permission.GET_INTENT_SENDER_INTENT\" />\n\n    <uses-permission\n        android:name=\"android.permission.WRITE_APN_SETTINGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <uses-feature android:name=\"android.hardware.camera\" />\n    <uses-feature\n        android:name=\"android.hardware.camera.autofocus\"\n        android:required=\"false\" />\n\n    <application>\n        <service\n            android:name=\"com.lody.virtual.client.stub.DaemonService\"\n            android:process=\"@string/engine_process_name\" />\n\n        <service\n            android:name=\"com.lody.virtual.client.stub.DaemonService$InnerService\"\n            android:process=\"@string/engine_process_name\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.ShortcutHandleActivity\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"va.task.shortcut\"\n            android:exported=\"true\"\n            android:process=\"@string/engine_process_name\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar\" />\n\n        <activity\n            android:name=\".client.stub.StubPendingActivity\"\n            android:process=\"@string/engine_process_name\" />\n\n        <service\n            android:name=\".client.stub.StubPendingService\"\n            android:process=\"@string/engine_process_name\" />\n        <receiver\n            android:name=\".client.stub.StubPendingReceiver\"\n            android:process=\"@string/engine_process_name\" />\n\n        <service\n            android:name=\".client.stub.StubJob\"\n            android:permission=\"android.permission.BIND_JOB_SERVICE\"\n            android:process=\"@string/engine_process_name\" />\n\n        <service\n            android:name=\".client.stub.DaemonJobService\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:permission=\"android.permission.BIND_JOB_SERVICE\"\n            android:process=\"@string/engine_process_name\" />\n\n        <activity\n            android:name=\".client.stub.ChooseAccountTypeActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:process=\"@string/engine_process_name\"\n            android:screenOrientation=\"portrait\" />\n\n        <activity\n            android:name=\".client.stub.ChooseTypeAndAccountActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:process=\"@string/engine_process_name\"\n            android:screenOrientation=\"portrait\" />\n\n        <activity\n            android:name=\".client.stub.ChooserActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:finishOnCloseSystemDialogs=\"true\"\n            android:process=\"@string/engine_process_name\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/VAAlertTheme\" />\n\n        <activity\n            android:name=\".client.stub.ResolverActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|orientation\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:finishOnCloseSystemDialogs=\"true\"\n            android:process=\"@string/engine_process_name\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/VAAlertTheme\" />\n\n        <provider\n            android:name=\"com.lody.virtual.server.BinderProvider\"\n            android:authorities=\"${applicationId}.virtual.service.BinderProvider\"\n            android:exported=\"false\"\n            android:process=\"@string/engine_process_name\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C0\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p0\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C1\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p1\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C2\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p2\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C3\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p3\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C4\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p4\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C5\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p5\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C6\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p6\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C7\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p7\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C8\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p8\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C9\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p9\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C10\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p10\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C11\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p11\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C12\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p12\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C13\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p13\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C14\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p14\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C15\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p15\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C16\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p16\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C17\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p17\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C18\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p18\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C19\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p19\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C20\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p20\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C21\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p21\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C22\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p22\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C23\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p23\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C24\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p24\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C25\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p25\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C26\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p26\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C27\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p27\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C28\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p28\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C29\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p29\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C30\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p30\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C31\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p31\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C32\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p32\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C33\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p33\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C34\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n\n            android:process=\":p34\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C35\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p35\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C36\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p36\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C37\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p37\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C38\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p38\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C39\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p39\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C40\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p40\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C41\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p41\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C42\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p42\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C43\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p43\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C44\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p44\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C45\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p45\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C46\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p46\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C47\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p47\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C48\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p48\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubActivity$C49\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p49\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C0\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p0\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C1\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p1\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C2\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p2\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C3\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p3\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C4\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p4\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C5\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p5\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C6\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p6\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C7\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p7\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C8\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p8\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C9\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p9\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C10\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p10\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C11\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p11\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C12\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p12\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C13\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p13\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C14\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p14\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C15\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p15\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C16\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p16\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C17\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p17\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C18\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p18\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C19\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p19\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C20\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p20\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C21\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p21\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C22\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p22\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C23\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p23\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C24\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p24\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C25\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p25\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C26\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p26\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C27\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p27\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C28\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p28\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C29\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p29\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C30\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p30\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C31\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p31\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C32\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p32\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C33\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p33\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C34\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p34\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C35\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p35\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C36\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p36\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C37\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p37\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C38\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p38\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C39\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p39\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C40\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p40\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C41\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p41\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C42\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p42\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C43\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p43\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C44\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p44\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C45\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p45\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C46\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p46\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C47\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p47\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C48\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p48\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubDialog$C49\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p49\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@android:style/Theme.Dialog\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C0\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p0\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C1\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p1\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C2\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p2\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C3\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p3\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C4\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p4\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C5\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p5\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C6\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p6\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C7\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p7\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C8\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p8\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C9\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p9\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C10\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p10\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C11\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p11\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C12\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p12\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C13\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p13\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C14\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p14\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C15\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p15\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C16\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p16\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C17\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p17\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C18\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p18\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C19\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p19\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C20\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p20\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C21\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p21\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C22\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p22\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C23\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p23\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C24\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p24\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C25\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p25\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C26\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p26\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C27\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p27\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C28\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p28\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C29\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p29\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C30\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p30\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C31\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p31\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C32\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p32\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C33\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p33\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C34\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p34\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C35\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p35\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C36\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p36\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C37\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p37\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C38\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p38\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C39\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p39\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C40\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p40\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C41\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p41\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C42\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p42\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C43\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p43\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C44\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p44\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C45\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p45\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C46\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p46\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C47\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p47\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C48\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p48\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <activity\n            android:name=\"com.lody.virtual.client.stub.StubExcludeFromRecentActivity$C49\"\n            android:configChanges=\"mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale\"\n            android:process=\":p49\"\n            android:excludeFromRecents=\"true\"\n            android:taskAffinity=\"com.lody.virtual.vt\"\n            android:theme=\"@style/VATheme\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C0\"\n            android:authorities=\"${applicationId}.virtual_stub_0\"\n            android:exported=\"false\"\n            android:process=\":p0\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C1\"\n            android:authorities=\"${applicationId}.virtual_stub_1\"\n            android:exported=\"false\"\n            android:process=\":p1\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C2\"\n            android:authorities=\"${applicationId}.virtual_stub_2\"\n            android:exported=\"false\"\n            android:process=\":p2\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C3\"\n            android:authorities=\"${applicationId}.virtual_stub_3\"\n            android:exported=\"false\"\n            android:process=\":p3\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C4\"\n            android:authorities=\"${applicationId}.virtual_stub_4\"\n            android:exported=\"false\"\n            android:process=\":p4\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C5\"\n            android:authorities=\"${applicationId}.virtual_stub_5\"\n            android:exported=\"false\"\n            android:process=\":p5\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C6\"\n            android:authorities=\"${applicationId}.virtual_stub_6\"\n            android:exported=\"false\"\n            android:process=\":p6\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C7\"\n            android:authorities=\"${applicationId}.virtual_stub_7\"\n            android:exported=\"false\"\n            android:process=\":p7\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C8\"\n            android:authorities=\"${applicationId}.virtual_stub_8\"\n            android:exported=\"false\"\n            android:process=\":p8\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C9\"\n            android:authorities=\"${applicationId}.virtual_stub_9\"\n            android:exported=\"false\"\n            android:process=\":p9\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C10\"\n            android:authorities=\"${applicationId}.virtual_stub_10\"\n            android:exported=\"false\"\n            android:process=\":p10\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C11\"\n            android:authorities=\"${applicationId}.virtual_stub_11\"\n            android:exported=\"false\"\n            android:process=\":p11\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C12\"\n            android:authorities=\"${applicationId}.virtual_stub_12\"\n            android:exported=\"false\"\n            android:process=\":p12\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C13\"\n            android:authorities=\"${applicationId}.virtual_stub_13\"\n            android:exported=\"false\"\n            android:process=\":p13\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C14\"\n            android:authorities=\"${applicationId}.virtual_stub_14\"\n            android:exported=\"false\"\n            android:process=\":p14\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C15\"\n            android:authorities=\"${applicationId}.virtual_stub_15\"\n            android:exported=\"false\"\n            android:process=\":p15\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C16\"\n            android:authorities=\"${applicationId}.virtual_stub_16\"\n            android:exported=\"false\"\n            android:process=\":p16\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C17\"\n            android:authorities=\"${applicationId}.virtual_stub_17\"\n            android:exported=\"false\"\n            android:process=\":p17\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C18\"\n            android:authorities=\"${applicationId}.virtual_stub_18\"\n            android:exported=\"false\"\n            android:process=\":p18\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C19\"\n            android:authorities=\"${applicationId}.virtual_stub_19\"\n            android:exported=\"false\"\n            android:process=\":p19\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C20\"\n            android:authorities=\"${applicationId}.virtual_stub_20\"\n            android:exported=\"false\"\n            android:process=\":p20\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C21\"\n            android:authorities=\"${applicationId}.virtual_stub_21\"\n            android:exported=\"false\"\n            android:process=\":p21\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C22\"\n            android:authorities=\"${applicationId}.virtual_stub_22\"\n            android:exported=\"false\"\n            android:process=\":p22\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C23\"\n            android:authorities=\"${applicationId}.virtual_stub_23\"\n            android:exported=\"false\"\n            android:process=\":p23\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C24\"\n            android:authorities=\"${applicationId}.virtual_stub_24\"\n            android:exported=\"false\"\n            android:process=\":p24\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C25\"\n            android:authorities=\"${applicationId}.virtual_stub_25\"\n            android:exported=\"false\"\n            android:process=\":p25\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C26\"\n            android:authorities=\"${applicationId}.virtual_stub_26\"\n            android:exported=\"false\"\n            android:process=\":p26\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C27\"\n            android:authorities=\"${applicationId}.virtual_stub_27\"\n            android:exported=\"false\"\n            android:process=\":p27\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C28\"\n            android:authorities=\"${applicationId}.virtual_stub_28\"\n            android:exported=\"false\"\n            android:process=\":p28\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C29\"\n            android:authorities=\"${applicationId}.virtual_stub_29\"\n            android:exported=\"false\"\n            android:process=\":p29\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C30\"\n            android:authorities=\"${applicationId}.virtual_stub_30\"\n            android:exported=\"false\"\n            android:process=\":p30\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C31\"\n            android:authorities=\"${applicationId}.virtual_stub_31\"\n            android:exported=\"false\"\n            android:process=\":p31\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C32\"\n            android:authorities=\"${applicationId}.virtual_stub_32\"\n            android:exported=\"false\"\n            android:process=\":p32\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C33\"\n            android:authorities=\"${applicationId}.virtual_stub_33\"\n            android:exported=\"false\"\n            android:process=\":p33\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C34\"\n            android:authorities=\"${applicationId}.virtual_stub_34\"\n            android:exported=\"false\"\n            android:process=\":p34\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C35\"\n            android:authorities=\"${applicationId}.virtual_stub_35\"\n            android:exported=\"false\"\n            android:process=\":p35\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C36\"\n            android:authorities=\"${applicationId}.virtual_stub_36\"\n            android:exported=\"false\"\n            android:process=\":p36\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C37\"\n            android:authorities=\"${applicationId}.virtual_stub_37\"\n            android:exported=\"false\"\n            android:process=\":p37\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C38\"\n            android:authorities=\"${applicationId}.virtual_stub_38\"\n            android:exported=\"false\"\n            android:process=\":p38\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C39\"\n            android:authorities=\"${applicationId}.virtual_stub_39\"\n            android:exported=\"false\"\n            android:process=\":p39\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C40\"\n            android:authorities=\"${applicationId}.virtual_stub_40\"\n            android:exported=\"false\"\n            android:process=\":p40\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C41\"\n            android:authorities=\"${applicationId}.virtual_stub_41\"\n            android:exported=\"false\"\n            android:process=\":p41\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C42\"\n            android:authorities=\"${applicationId}.virtual_stub_42\"\n            android:exported=\"false\"\n            android:process=\":p42\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C43\"\n            android:authorities=\"${applicationId}.virtual_stub_43\"\n            android:exported=\"false\"\n            android:process=\":p43\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C44\"\n            android:authorities=\"${applicationId}.virtual_stub_44\"\n            android:exported=\"false\"\n            android:process=\":p44\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C45\"\n            android:authorities=\"${applicationId}.virtual_stub_45\"\n            android:exported=\"false\"\n            android:process=\":p45\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C46\"\n            android:authorities=\"${applicationId}.virtual_stub_46\"\n            android:exported=\"false\"\n            android:process=\":p46\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C47\"\n            android:authorities=\"${applicationId}.virtual_stub_47\"\n            android:exported=\"false\"\n            android:process=\":p47\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C48\"\n            android:authorities=\"${applicationId}.virtual_stub_48\"\n            android:exported=\"false\"\n            android:process=\":p48\" />\n\n        <provider\n            android:name=\"com.lody.virtual.client.stub.StubCP$C49\"\n            android:authorities=\"${applicationId}.virtual_stub_49\"\n            android:exported=\"false\"\n            android:process=\":p49\" />\n\n    </application>\n</manifest>"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/accounts/IAccountAuthenticator.aidl",
    "content": "/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.accounts;\n\nimport android.accounts.IAccountAuthenticatorResponse;\nimport android.accounts.Account;\nimport android.os.Bundle;\n\n/**\n * Service that allows the interaction with an authentication server.\n * @hide\n */\ninterface IAccountAuthenticator {\n    /**\n     * prompts the user for account information and adds the result to the IAccountManager\n     */\n    void addAccount(in IAccountAuthenticatorResponse response, String accountType,\n        String authTokenType, in String[] requiredFeatures, in Bundle options);\n\n    /**\n     * prompts the user for the credentials of the account\n     */\n    void confirmCredentials(in IAccountAuthenticatorResponse response, in Account account,\n        in Bundle options);\n\n    /**\n     * gets the password by either prompting the user or querying the IAccountManager\n     */\n    void getAuthToken(in IAccountAuthenticatorResponse response, in Account account,\n        String authTokenType, in Bundle options);\n\n    /**\n     * Gets the user-visible label of the given authtoken type.\n     */\n    void getAuthTokenLabel(in IAccountAuthenticatorResponse response, String authTokenType);\n\n    /**\n     * prompts the user for a new password and writes it to the IAccountManager\n     */\n    void updateCredentials(in IAccountAuthenticatorResponse response, in Account account,\n        String authTokenType, in Bundle options);\n\n    /**\n     * launches an activity that lets the user edit and set the properties for an authenticator\n     */\n    void editProperties(in IAccountAuthenticatorResponse response, String accountType);\n\n    /**\n     * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the\n     * specified features\n     */\n    void hasFeatures(in IAccountAuthenticatorResponse response, in Account account, \n        in String[] features);\n\n    /**\n     * Gets whether or not the account is allowed to be removed.\n     */\n    void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);\n\n    /**\n     * Returns a Bundle containing the required credentials to copy the account across users.\n     */\n    void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,\n            in Account account);\n\n    /**\n     * Uses the Bundle containing credentials from another instance of the authenticator to create\n     * a copy of the account on this user.\n     */\n    void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,\n            in Bundle accountCredentials);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/accounts/IAccountAuthenticatorResponse.aidl",
    "content": "/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.accounts;\nimport android.os.Bundle;\n\n/**\n * The interface used to return responses from an {@link IAccountAuthenticator}\n */\ninterface IAccountAuthenticatorResponse {\n    void onResult(in Bundle value);\n    void onRequestContinued();\n    void onError(int errorCode, String errorMessage);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/accounts/IAccountManagerResponse.aidl",
    "content": "package android.accounts;\n\nimport android.os.Bundle;\n\n/**\n * The interface used to return responses for asynchronous calls to the {@link IAccountManager}\n */\ninterface IAccountManagerResponse {\n    void onResult(in Bundle value);\n    void onError(int errorCode, String errorMessage);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/app/IActivityManager/ContentProviderHolder.aidl",
    "content": "// ContentProviderHolder.aidl\npackage android.app.IActivityManager;\n\nparcelable ContentProviderHolder;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/app/IServiceConnection.aidl",
    "content": "/* //device/java/android/android/app/IServiceConnection.aidl\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n\npackage android.app;\n\nimport android.content.ComponentName;\n\n/** @hide */\ninterface IServiceConnection {\n    void connected(in ComponentName name, IBinder service);\n}\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/app/IStopUserCallback.aidl",
    "content": "/*\n** Copyright 2012, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\");\n** you may not use this file except in compliance with the License.\n** You may obtain a copy of the License at\n**\n**     http://www.apache.org/licenses/LICENSE-2.0\n**\n** Unless required by applicable law or agreed to in writing, software\n** distributed under the License is distributed on an \"AS IS\" BASIS,\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n** See the License for the specific language governing permissions and\n** limitations under the License.\n*/\n\npackage android.app;\n\n/**\n * Callback to find out when we have finished stopping a user.\n * {@hide}\n */\ninterface IStopUserCallback\n{\n    void userStopped(int userId);\n    void userStopAborted(int userId);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/app/job/IJobCallback.aidl",
    "content": "/**\n * Copyright 2014, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.app.job;\n\n/**\n * The server side of the JobScheduler IPC protocols.  The app-side implementation\n * invokes on this interface to indicate completion of the (asynchronous) instructions\n * issued by the server.\n *\n * In all cases, the 'who' parameter is the caller's service binder, used to track\n * which Job Service instance is reporting.\n *\n */\ninterface IJobCallback {\n    /**\n     * Immediate callback to the system after sending a start signal, used to quickly detect ANR.\n     *\n     * @param jobId Unique integer used to identify this job.\n     * @param ongoing True to indicate that the client is processing the job. False if the job is\n     * complete\n     */\n    void acknowledgeStartMessage(int jobId, boolean ongoing);\n    /**\n     * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.\n     *\n     * @param jobId Unique integer used to identify this job.\n     * @param reschedule Whether or not to reschedule this job.\n     */\n    void acknowledgeStopMessage(int jobId, boolean reschedule);\n    /*\n     * Tell the job manager that the client is done with its execution, so that it can go on to\n     * the next one and stop attributing wakelock time to us etc.\n     *\n     * @param jobId Unique integer used to identify this job.\n     * @param reschedule Whether or not to reschedule this job.\n     */\n    void jobFinished(int jobId, boolean reschedule);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/app/job/IJobService.aidl",
    "content": "package android.app.job;\n\nimport android.app.job.JobParameters;\n\n/**\n * Interface that the framework uses to communicate with application code that implements a\n * JobService.  End user code does not implement this interface directly; instead, the app's\n * service implementation will extend android.app.job.JobService.\n */\ninterface IJobService {\n    /** Begin execution of application's job. */\n    void startJob(in JobParameters jobParams);\n    /** Stop execution of application's job. */\n    void stopJob(in JobParameters jobParams);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/IIntentReceiver.aidl",
    "content": "/*\n * Copyright (C) 2006 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.content;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\n/**\n * System private API for dispatching intent broadcasts.  This is given to the\n * activity manager as part of registering for an intent broadcasts, and is\n * called when it receives intents.\n *\n */\ninterface IIntentReceiver {\n    void performReceive(in Intent intent, int resultCode, String data,\n            in Bundle extras, boolean ordered, boolean sticky, int sendingUser);\n}\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/ISyncAdapter.aidl",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.content;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\nimport android.content.ISyncContext;\n\n/**\n * Interface used to control the sync activity on a SyncAdapter\n */\ninterface ISyncAdapter {\n    /**\n     * Initiate a sync for this account. SyncAdapter-specific parameters may\n     * be specified in extras, which is guaranteed to not be null.\n     *\n     * @param syncContext the ISyncContext used to indicate the progress of the sync. When\n     *   the sync is finished (successfully or not) ISyncContext.onFinished() must be called.\n     * @param authority the authority that should be synced\n     * @param account the account that should be synced\n     * @param extras SyncAdapter-specific parameters\n     */\n    void startSync(ISyncContext syncContext, String authority,\n      in Account account, in Bundle extras);\n\n    /**\n     * Cancel the most recently initiated sync. Due to race conditions, this may arrive\n     * after the ISyncContext.onFinished() for that sync was called.\n     * @param syncContext the ISyncContext that was passed to {@link #startSync}\n     */\n    void cancelSync(ISyncContext syncContext);\n\n    /**\n     * Initialize the SyncAdapter for this account and authority.\n     *\n     * @param account the account that should be synced\n     * @param authority the authority that should be synced\n     */\n    void initialize(in Account account, String authority);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/ISyncContext.aidl",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.content;\n\nimport android.content.SyncResult;\n\n/**\n * Interface used by the SyncAdapter to indicate its progress.\n * @hide\n */\ninterface ISyncContext {\n    /**\n     * Call to indicate that the SyncAdapter is making progress. E.g., if this SyncAdapter\n     * downloads or sends records to/from the server, this may be called after each record\n     * is downloaded or uploaded.\n     */\n    void sendHeartbeat();\n\n    /**\n     * Signal that the corresponding sync session is completed.\n     * @param result information about this sync session\n     */\n    void onFinished(in SyncResult result);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/ISyncStatusObserver.aidl",
    "content": "package android.content;\n\n\ninterface ISyncStatusObserver {\n    void onStatusChanged(int which);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageDataObserver.aidl",
    "content": "package android.content.pm;\n\n/**\n * API for package data change related callbacks from the Package Manager.\n * Some usage scenarios include deletion of cache directory, generate\n * statistics related to code, data, cache usage(TODO)\n */\ninterface IPackageDataObserver {\n    void onRemoveCompleted(in String packageName, boolean succeeded);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.content.pm;\n\nimport android.content.Intent;\n\ninterface IPackageDeleteObserver2 {\n    void onUserActionRequired(in Intent intent);\n    void onPackageDeleted(String packageName, int returnCode, String msg);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageInstallObserver.aidl",
    "content": "package android.content.pm;\n\n/**\n * API for installation callbacks from the Package Manager.\n */\ninterface IPackageInstallObserver {\n    void packageInstalled(in String packageName, int returnCode);\n}\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.content.pm;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\n/**\n * API for installation callbacks from the Package Manager.  In certain result cases\n * additional information will be provided.\n */\ninterface IPackageInstallObserver2 {\n    void onUserActionRequired(in Intent intent);\n\n    /**\n     * The install operation has completed.  {@code returnCode} holds a numeric code\n     * indicating success or failure.  In certain cases the {@code extras} Bundle will\n     * contain additional details:\n     *\n     * <p><table>\n     * <tr>\n     *   <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td>\n     *   <td>Two strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION\n     *       is the name of the permission that the app is attempting to define, and\n     *       EXTRA_EXISTING_PACKAGE is the package name of the app which has already\n     *       defined the permission.</td>\n     * </tr>\n     * </table>\n     */\n    void onPackageInstalled(String basePackageName, int returnCode, String msg, in Bundle extras);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl",
    "content": "package android.content.pm;\n\ninterface IPackageInstallerCallback {\n    void onSessionCreated(int sessionId);\n    void onSessionBadgingChanged(int sessionId);\n    void onSessionActiveChanged(int sessionId, boolean active);\n    void onSessionProgressChanged(int sessionId, float progress);\n    void onSessionFinished(int sessionId, boolean success);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl",
    "content": "package android.content.pm;\n\nimport android.content.pm.IPackageInstallObserver2;\nimport android.content.IntentSender;\nimport android.os.ParcelFileDescriptor;\n\ninterface IPackageInstallerSession {\n    void setClientProgress(float progress);\n    void addClientProgress(float progress);\n\n    String[] getNames();\n    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);\n    ParcelFileDescriptor openRead(String name);\n\n    void removeSplit(String splitName);\n\n    void close();\n    void commit(in IntentSender statusReceiver);\n    void abandon();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/location/ILocationListener.aidl",
    "content": "// ILocationListener.aidl\npackage android.location;\n\nimport android.location.Location;\nimport android.os.Bundle;\n\ninterface ILocationListener\n{\n    void onLocationChanged(in Location location);\n    void onStatusChanged(String provider, int status, in Bundle extras);\n    void onProviderEnabled(String provider);\n    void onProviderDisabled(String provider);\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/net/IConnectivityManager.aidl",
    "content": "package android.net;\n\nimport android.net.NetworkInfo;\nimport android.net.LinkProperties;\n\ninterface IConnectivityManager {\n\n    NetworkInfo getActiveNetworkInfo();\n    NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);\n\n    NetworkInfo getNetworkInfo(int networkType);\n    NetworkInfo[] getAllNetworkInfo();\n    boolean isActiveNetworkMetered();\n    boolean requestRouteToHostAddress(int networkType, int address);\n    LinkProperties getActiveLinkProperties();\n    LinkProperties getLinkProperties(int networkType);\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/android/net/wifi/IWifiScanner.aidl",
    "content": "package android.net.wifi;\n\nimport android.os.Messenger;\nimport android.os.Bundle;\n\ninterface IWifiScanner\n{\n    Messenger getMessenger();\n\n    Bundle getAvailableChannels(int band);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/client/IVClient.aidl",
    "content": "// IVClient.aidl\npackage com.lody.virtual.client;\n\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ProviderInfo;\n\nimport com.lody.virtual.remote.PendingResultData;\n\ninterface IVClient {\n    void scheduleReceiver(in String processName,in ComponentName component, in Intent intent, in PendingResultData resultData);\n    void scheduleNewIntent(in String creator, in IBinder token, in Intent intent);\n    void finishActivity(in IBinder token);\n    IBinder createProxyService(in ComponentName component, in IBinder binder);\n    IBinder acquireProviderClient(in ProviderInfo info);\n    IBinder getAppThread();\n    IBinder getToken();\n    String getDebugInfo();\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/os/VUserInfo.aidl",
    "content": "// VUserInfo.aidl\npackage com.lody.virtual.os;\n\nparcelable VUserInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/AppTaskInfo.aidl",
    "content": "// AppTaskInfo.aidl\npackage com.lody.virtual.remote;\n\nparcelable AppTaskInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/BadgerInfo.aidl",
    "content": "// BadgerInfo.aidl\npackage com.lody.virtual.remote;\n\nparcelable BadgerInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/InstallResult.aidl",
    "content": "// InstallResult.aidl\npackage com.lody.virtual.remote;\n\nparcelable InstallResult;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/InstalledAppInfo.aidl",
    "content": "// AppSetting.aidl\npackage com.lody.virtual.remote;\n\nparcelable InstalledAppInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/PendingIntentData.aidl",
    "content": "// PendingIntentData.aidl\npackage com.lody.virtual.remote;\n\nparcelable PendingIntentData;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/PendingResultData.aidl",
    "content": "// PendingResultData.aidl\npackage com.lody.virtual.remote;\n\nparcelable PendingResultData;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/Problem.aidl",
    "content": "// Problem.aidl\npackage com.lody.virtual.remote;\n\nparcelable Problem;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/ReceiverInfo.aidl",
    "content": "// ReceiverInfo.aidl\npackage com.lody.virtual.remote;\n\nparcelable ReceiverInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/VDeviceInfo.aidl",
    "content": "// VDeviceInfo.aidl\npackage com.lody.virtual.remote;\n\nparcelable VDeviceInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/VParceledListSlice.aidl",
    "content": "// VParceledListSlice.aidl\npackage com.lody.virtual.remote;\n\nparcelable VParceledListSlice;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/vloc/VCell.aidl",
    "content": "// VCell.aidl\npackage com.lody.virtual.remote.vloc;\n\nparcelable VCell;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/vloc/VLocation.aidl",
    "content": "// VLocation.aidl\npackage com.lody.virtual.remote.vloc;\n\nparcelable VLocation;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/remote/vloc/VWifi.aidl",
    "content": "// VWifi.aidl\npackage com.lody.virtual.remote.vloc;\n\nparcelable VWifi;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAccountManager.aidl",
    "content": "package com.lody.virtual.server;\n\nimport android.accounts.IAccountManagerResponse;\nimport android.accounts.Account;\nimport android.accounts.AuthenticatorDescription;\nimport android.os.Bundle;\n\n\n/**\n * Central application service that provides account management.\n * @hide\n */\ninterface IAccountManager {\n    AuthenticatorDescription[] getAuthenticatorTypes(int userId);\n    void getAccountsByFeatures(int userId, in IAccountManagerResponse response, in String type, in String[] features);\n    String getPreviousName(int userId, in Account account);\n    Account[] getAccounts(int userId, in String type);\n    void getAuthToken(int userId, in IAccountManagerResponse response, in Account account, in String authTokenType, in boolean notifyOnAuthFailure, in boolean expectActivityLaunch, in Bundle loginOptions);\n    void setPassword(int userId, in Account account, in String password);\n    void setAuthToken(int userId, in Account account, in String authTokenType, in String authToken);\n    void setUserData(int userId, in Account account, in String key, in String value);\n    void hasFeatures(int userId, in IAccountManagerResponse response,\n    \t\t\t\t\t\t\tin Account account, in String[] features);\n    void updateCredentials(int userId, in IAccountManagerResponse response, in Account account,\n    \t\t\t\t\t\t\t\t  in String authTokenType, in boolean expectActivityLaunch,\n    \t\t\t\t\t\t\t\t  in Bundle loginOptions);\n    void editProperties(int userId, in IAccountManagerResponse response, in String accountType,\n    \t\t\t\t\t\t\t   in boolean expectActivityLaunch);\n    void getAuthTokenLabel(int userId, in IAccountManagerResponse response, in String accountType,\n    \t\t\t\t\t\t\t\t  in String authTokenType);\n    String getUserData(int userId, in Account account, in String key);\n    String getPassword(int userId, in Account account);\n    void confirmCredentials(int userId, in IAccountManagerResponse response, in Account account, in Bundle options, in boolean expectActivityLaunch);\n    void addAccount(int userId, in IAccountManagerResponse response, in String accountType,\n    \t\t\t\t\t\t   in String authTokenType, in String[] requiredFeatures,\n    \t\t\t\t\t\t   in boolean expectActivityLaunch, in Bundle optionsIn);\n    boolean addAccountExplicitly(int userId, in Account account, in String password, in Bundle extras);\n    boolean removeAccountExplicitly(int userId, in Account account);\n    void renameAccount(int userId, in IAccountManagerResponse response, in Account accountToRename, in String newName);\n    void removeAccount(in int userId, in IAccountManagerResponse response, in Account account,\n    \t\t\t\t\t\t\t  in boolean expectActivityLaunch);\n    void clearPassword(int userId, in Account account);\n    boolean accountAuthenticated(int userId, in Account account);\n    void invalidateAuthToken(int userId, in String accountType, in String authToken);\n    String peekAuthToken(int userId, in Account account, in String authTokenType);\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IActivityManager.aidl",
    "content": "// IActivityManager.aidl\npackage com.lody.virtual.server;\n\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.remote.AppTaskInfo;\nimport com.lody.virtual.remote.PendingIntentData;\nimport com.lody.virtual.remote.PendingResultData;\nimport com.lody.virtual.remote.BadgerInfo;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.app.Notification;\nimport android.app.IServiceConnection;\nimport android.app.IActivityManager.ContentProviderHolder;\nimport com.lody.virtual.server.interfaces.IProcessObserver;\n\n\ninterface IActivityManager {\n\n    int initProcess(in String packageName, in String processName, int userId);\n\n    int getFreeStubCount();\n\n    int getSystemPid();\n\n    int getUidByPid(int pid);\n\n    boolean isAppProcess(String processName);\n\n    boolean isAppRunning(String packageName, int userId);\n\n    boolean isAppPid(int pid);\n\n    String getAppProcessName(int pid);\n\n    List<String> getProcessPkgList(int pid);\n\n    void killAllApps();\n\n    void killAppByPkg(String pkg, int userId);\n\n    void killApplicationProcess(String procName, int vuid);\n\n    void dump();\n\n    void registerProcessObserver(in IProcessObserver observer);\n\n    void unregisterProcessObserver(in IProcessObserver observer);\n\n    String getInitialPackage(int pid);\n\n    void handleApplicationCrash();\n\n    void appDoneExecuting();\n\n    int startActivities(in Intent[] intents, in String[] resolvedTypes, in IBinder token, in Bundle options, in int userId);\n\n    int startActivity(in Intent intent, in ActivityInfo info, in IBinder resultTo, in Bundle options, String resultWho, int requestCode, int userId);\n\n    void onActivityCreated(in ComponentName component, in ComponentName caller, in IBinder token, in Intent intent, in String affinity, int taskId, int launchMode, int flags);\n\n    void onActivityResumed(int userId, in IBinder token);\n\n    boolean onActivityDestroyed(int userId, in IBinder token);\n\n    ComponentName getActivityClassForToken(int userId, in IBinder token);\n\n    String getCallingPackage(int userId, in IBinder token);\n\n    ComponentName getCallingActivity(int userId, in IBinder token);\n\n    AppTaskInfo getTaskInfo(int taskId);\n\n    String getPackageForToken(int userId, in IBinder token);\n\n    boolean isVAServiceToken(in IBinder token);\n\n    ComponentName startService(in IBinder caller,in Intent service, String resolvedType, int userId);\n\n    int stopService(in IBinder caller, in Intent service, String resolvedType, int userId);\n\n    boolean stopServiceToken(in ComponentName className, in IBinder token, int startId, int userId);\n\n    void setServiceForeground(in ComponentName className, in IBinder token, int id,\n                            in Notification notification, boolean removeNotification, int userId);\n\n    int bindService(in IBinder caller, in IBinder token, in Intent service,\n                    String resolvedType, in IServiceConnection connection, int flags, int userId);\n\n    boolean unbindService(in IServiceConnection connection, int userId);\n\n    void unbindFinished(in IBinder token, in Intent service, in boolean doRebind, int userId);\n\n    void serviceDoneExecuting(in IBinder token, in int type, in int startId, in int res, int userId);\n\n    IBinder peekService(in Intent service, String resolvedType, int userId);\n\n    void publishService(in IBinder token, in Intent intent, in IBinder service, int userId);\n\n    VParceledListSlice getServices(int maxNum, int flags, int userId);\n\n    IBinder acquireProviderClient(int userId, in ProviderInfo info);\n\n    PendingIntentData getPendingIntent(IBinder binder);\n\n    void addPendingIntent(IBinder binder, String packageName);\n\n    void removePendingIntent(IBinder binder);\n\n    String getPackageForIntentSender(IBinder binder);\n\n    void processRestarted(in String packageName, in String processName, int userId);\n\n    void broadcastFinish(in PendingResultData res);\n\n    void notifyBadgerChange(in BadgerInfo info);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IAppManager.aidl",
    "content": "// IAppManager.aidl\npackage com.lody.virtual.server;\n\nimport com.lody.virtual.server.interfaces.IPackageObserver;\nimport com.lody.virtual.server.interfaces.IAppRequestListener;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.remote.InstallResult;\n\ninterface IAppManager {\n    int[] getPackageInstalledUsers(String packageName);\n    void scanApps();\n    void addVisibleOutsidePackage(String pkg);\n    void removeVisibleOutsidePackage(String pkg);\n    boolean isOutsidePackageVisible(String pkg);\n    InstalledAppInfo getInstalledAppInfo(String pkg, int flags);\n    InstallResult installPackage(String path, int flags);\n    boolean isPackageLaunched(int userId, String packageName);\n    void setPackageHidden(int userId, String packageName, boolean hidden);\n    boolean installPackageAsUser(int userId, String packageName);\n    boolean uninstallPackageAsUser(String packageName, int userId);\n    boolean uninstallPackage(String packageName);\n    boolean clearPackageAsUser(int userId, String packageName);\n    boolean clearPackage(String packageName);\n    List<InstalledAppInfo> getInstalledApps(int flags);\n    List<InstalledAppInfo> getInstalledAppsAsUser(int userId, int flags);\n    int getInstalledAppCount();\n    boolean isAppInstalled(String packageName);\n    boolean isAppInstalledAsUser(int userId, String packageName);\n\n    void registerObserver(IPackageObserver observer);\n    void unregisterObserver(IPackageObserver observer);\n\n    void setAppRequestListener(IAppRequestListener listener);\n    void clearAppRequestListener();\n    IAppRequestListener getAppRequestListener();\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IBinderDelegateService.aidl",
    "content": "// IBinderDelegateService.aidl\npackage com.lody.virtual.server;\n\nimport android.content.ComponentName;\n\ninterface IBinderDelegateService {\n\n   ComponentName getComponent();\n\n   IBinder getService();\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IDeviceInfoManager.aidl",
    "content": "// IDeviceInfoManager.aidl\npackage com.lody.virtual.server;\n\nimport com.lody.virtual.remote.VDeviceInfo;\n\ninterface IDeviceInfoManager {\n\n    VDeviceInfo getDeviceInfo(int userId);\n\n    void updateDeviceInfo(int userId, in VDeviceInfo info);\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IJobScheduler.aidl",
    "content": "//package com.lody.virtual.server;\n//\n//import android.app.job.JobInfo;\n//import android.app.job.JobParameters;\n//\n// /**\n//  * IPC interface that supports the app-facing {@link #JobScheduler} api.\n//  */\n//interface IJobScheduler {\n//    int schedule(in JobInfo job);\n//    void cancel(int jobId);\n//    void cancelAll();\n//    List<JobInfo> getAllPendingJobs();\n//    int enqueue(in JobInfo job, in JobParameters work);\n//    JobInfo getPendingJob(int i);\n//}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/INotificationManager.aidl",
    "content": "// INotificationManager.aidl\r\npackage com.lody.virtual.server;\r\n\r\n// Declare any non-default types here with import statements\r\nimport android.app.Notification;\r\n\r\ninterface INotificationManager {\r\n    int dealNotificationId(int id, String packageName, String tag, int userId);\r\n    String dealNotificationTag(int id, String packageName, String tag, int userId);\r\n    boolean areNotificationsEnabledForPackage(String packageName, int userId);\r\n    void setNotificationsEnabledForPackage(String packageName, boolean enable, int userId);\r\n    void addNotification(int id, String tag, String packageName, int userId);\r\n    void cancelAllNotification(String packageName, int userId);\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageInstaller.aidl",
    "content": "package com.lody.virtual.server;\n\nimport android.content.pm.IPackageDeleteObserver2;\nimport android.content.pm.IPackageInstallerCallback;\nimport android.content.pm.IPackageInstallerSession;\nimport android.content.IntentSender;\nimport android.graphics.Bitmap;\n\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.server.pm.installer.SessionParams;\nimport com.lody.virtual.server.pm.installer.SessionInfo;\n\ninterface IPackageInstaller {\n    int createSession(in SessionParams params, String installerPackageName, int userId);\n\n    void updateSessionAppIcon(int sessionId, in Bitmap appIcon);\n    void updateSessionAppLabel(int sessionId, String appLabel);\n\n    void abandonSession(int sessionId);\n\n    IPackageInstallerSession openSession(int sessionId);\n\n    SessionInfo getSessionInfo(int sessionId);\n\n    VParceledListSlice getAllSessions(int userId);\n    VParceledListSlice getMySessions(String installerPackageName, int userId);\n\n    void registerCallback(IPackageInstallerCallback callback, int userId);\n    void unregisterCallback(IPackageInstallerCallback callback);\n\n    void uninstall(String packageName, String callerPackageName, int flags,\n            in IntentSender statusReceiver, int userId);\n\n    void setPermissionsResult(int sessionId, boolean accepted);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageInstallerSession.aidl",
    "content": "package com.lody.virtual.server;\n\nimport android.content.IntentSender;\nimport android.os.ParcelFileDescriptor;\n\ninterface IPackageInstallerSession {\n    void setClientProgress(float progress);\n    void addClientProgress(float progress);\n\n    String[] getNames();\n    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);\n    ParcelFileDescriptor openRead(String name);\n    void close();\n    void commit(in IntentSender statusReceiver);\n    void abandon();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IPackageManager.aidl",
    "content": "// IPackageManager.aidl\npackage com.lody.virtual.server;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.IntentFilter;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.PermissionGroupInfo;\n\nimport com.lody.virtual.remote.ReceiverInfo;\nimport com.lody.virtual.remote.VParceledListSlice;\n\nimport com.lody.virtual.server.IPackageInstaller;\n\ninterface IPackageManager {\n\n        int getPackageUid(String packageName, int userId);\n\n        String[] getPackagesForUid(int vuid);\n\n        List<String> getSharedLibraries(String pkgName);\n\n        int checkPermission(String permName, String pkgName, int userId);\n\n        PackageInfo getPackageInfo(String packageName, int flags, int userId);\n\n        ActivityInfo getActivityInfo(in ComponentName componentName, int flags, int userId);\n\n        boolean activitySupportsIntent(in ComponentName component, in Intent intent,\n                                           \t\t\t\t\t\t\t\t\t\t  in String resolvedType);\n         ActivityInfo getReceiverInfo(in ComponentName componentName, int flags, int userId);\n\n         ServiceInfo getServiceInfo(in ComponentName componentName, int flags, int userId);\n\n         ProviderInfo getProviderInfo(in ComponentName componentName, int flags, int userId);\n\n         ResolveInfo resolveIntent(in Intent intent, in String resolvedType, int flags, int userId);\n\n         List<ResolveInfo> queryIntentActivities(in Intent intent,in  String resolvedType, int flags, int userId);\n\n         List<ResolveInfo> queryIntentReceivers(in Intent intent, String resolvedType, int flags, int userId);\n\n         ResolveInfo resolveService(in Intent intent, String resolvedType, int flags, int userId);\n\n         List<ResolveInfo> queryIntentServices(in Intent intent, String resolvedType, int flags, int userId);\n\n         List<ResolveInfo> queryIntentContentProviders(in Intent intent, String resolvedType, int flags, int userId);\n\n         VParceledListSlice getInstalledPackages(int flags, int userId);\n\n         VParceledListSlice getInstalledApplications(int flags, int userId);\n\n         PermissionInfo getPermissionInfo(in String name, int flags);\n\n         List<PermissionInfo> queryPermissionsByGroup(in String group, int flags);\n\n         PermissionGroupInfo getPermissionGroupInfo(in String name, int flags);\n\n         List<PermissionGroupInfo> getAllPermissionGroups(int flags);\n\n         ProviderInfo resolveContentProvider(in String name, int flags, int userId);\n\n         ApplicationInfo getApplicationInfo(in String packageName, int flags, int userId);\n\n         VParceledListSlice queryContentProviders(in String processName, int vuid, int flags);\n\n         List<String> querySharedPackages(in String packageName);\n\n         String getNameForUid(int uid);\n\n         IPackageInstaller getPackageInstaller();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IUserManager.aidl",
    "content": "package com.lody.virtual.server;\n\nimport android.os.ParcelFileDescriptor;\nimport com.lody.virtual.os.VUserInfo;\nimport android.graphics.Bitmap;\n\n/**\n*\n */\ninterface IUserManager {\n    VUserInfo createUser(in String name, int flags);\n    boolean removeUser(int userHandle);\n    void setUserName(int userHandle, String name);\n    void setUserIcon(int userHandle, in Bitmap icon);\n    Bitmap getUserIcon(int userHandle);\n    List<VUserInfo> getUsers(boolean excludeDying);\n    VUserInfo getUserInfo(int userHandle);\n    void setGuestEnabled(boolean enable);\n    boolean isGuestEnabled();\n    void wipeUser(int userHandle);\n    int getUserSerialNumber(int userHandle);\n    int getUserHandle(int userSerialNumber);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualLocationManager.aidl",
    "content": "// IVirtualLocationManager.aidl\npackage com.lody.virtual.server;\n\nimport com.lody.virtual.remote.vloc.VCell;\nimport com.lody.virtual.remote.vloc.VWifi;\nimport com.lody.virtual.remote.vloc.VLocation;\n\ninterface IVirtualLocationManager {\n\n    int getMode(int userId, in String pkg);\n    void setMode(int userId, in String pkg, int mode);\n\n    void setCell(in int userId, in String pkg, in VCell cell);\n    void setAllCell(in int userId, in String pkg, in List<VCell> cell);\n    void setNeighboringCell(in int userId, in String pkg, in List<VCell> cell);\n\n    void setGlobalCell(in VCell cell);\n    void setGlobalAllCell(in List<VCell> cell);\n    void setGlobalNeighboringCell(in List<VCell> cell);\n\n    VCell getCell(in int userId, in String pkg);\n    List<VCell> getAllCell(in int userId, in String pkg);\n    List<VCell> getNeighboringCell(in int userId, in String pkg);\n\n    void setLocation(in int userId, in String pkg, in VLocation loc);\n    VLocation getLocation(in int userId, in String pkg);\n\n    void setGlobalLocation(in VLocation loc);\n    VLocation getGlobalLocation();\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IVirtualStorageService.aidl",
    "content": "// IVirtualStorageService.aidl\npackage com.lody.virtual.server;\n\n\ninterface IVirtualStorageService {\n\n   void setVirtualStorage(in String packageName, in int userId, in String vsPath);\n\n   String getVirtualStorage(in String packageName, in int userId);\n\n   void setVirtualStorageState(in String packageName, in int userId, in boolean enable);\n\n   boolean isVirtualStorageEnable(in String packageName, in int userId);\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IAppRequestListener.aidl",
    "content": "// IAppRequestListener.aidl\npackage com.lody.virtual.server.interfaces;\n\ninterface IAppRequestListener {\n    void onRequestInstall(in String path);\n    void onRequestUninstall(in String pkg);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IIntentFilterObserver.aidl",
    "content": "// IIntentFilterObserver.aidl\npackage com.lody.virtual.server.interfaces;\n\n// Declare any non-default types here with import statements\n\ninterface IIntentFilterObserver {\n    /**\n     * Demonstrates some basic types that you can use as parameters\n     * and return values in AIDL.\n     */\n\n     Intent filter(in Intent intent);\n     void setCallBack(IBinder callBack);\n     IBinder getCallBack();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IPackageObserver.aidl",
    "content": "// IPackageObserver.aidl\npackage com.lody.virtual.server.interfaces;\n\ninterface IPackageObserver {\n    void onPackageInstalled(in String packageName);\n    void onPackageUninstalled(in String packageName);\n    void onPackageInstalledAsUser(in int userId, in String packageName);\n    void onPackageUninstalledAsUser(in int userId, in String packageName);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IProcessObserver.aidl",
    "content": "// IProcessObserver.aidl\npackage com.lody.virtual.server.interfaces;\n\ninterface IProcessObserver {\n    void onProcessCreated(in String pkg, in String processName);\n\n    void onProcessDied(in String pkg, in String processName);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IServiceFetcher.aidl",
    "content": "// IServiceFetcher.aidl\npackage com.lody.virtual.server.interfaces;\n\ninterface IServiceFetcher {\n    IBinder getService(String name);\n    void addService(String name,in IBinder service);\n    void removeService(String name);\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/interfaces/IUiCallback.aidl",
    "content": "// IUiCallback.aidl\npackage com.lody.virtual.server.interfaces;\n\ninterface IUiCallback {\n    void onAppOpened(in String packageName, in int userId);\n    void onOpenFailed(in String packageName, in int userId);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/pm/installer/SessionInfo.aidl",
    "content": "// SessionInfo.aidl\npackage com.lody.virtual.server.pm.installer;\n\nparcelable SessionInfo;"
  },
  {
    "path": "VirtualApp/lib/src/main/aidl/com/lody/virtual/server/pm/installer/SessionParams.aidl",
    "content": "// SessionParams.aidl\npackage com.lody.virtual.server.pm.installer;\n\nparcelable SessionParams;"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/ActivityOptions.java",
    "content": "package android.app;\n\n/**\n * @author weishu\n * @date 2021/2/24.\n */\n\nclass ActivityOptions {\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/ActivityThread.java",
    "content": "package android.app;\n\n/**\n * @author weishu\n * @date 2018/8/7.\n */\npublic class ActivityThread {\n    public static class ActivityClientRecord {}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/ClientTransactionHandler.java",
    "content": "/*\n * Copyright 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage android.app;\n\nimport android.app.servertransaction.ClientTransaction;\nimport android.app.servertransaction.PendingTransactionActions;\nimport android.app.servertransaction.TransactionExecutor;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.res.CompatibilityInfo;\nimport android.content.res.Configuration;\nimport android.os.IBinder;\nimport android.os.Parcelable;\nimport android.util.MergedConfiguration;\nimport android.view.DisplayAdjustments;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.com.android.internal.content.ReferrerIntent;\n\n/**\n * Defines operations that a {@link ClientTransaction} or its items\n * can perform on client.\n * @hide\n */\npublic abstract class ClientTransactionHandler {\n\n    // Schedule phase related logic and handlers.\n    /** Prepare and schedule transaction for execution. */\n    void scheduleTransaction(ClientTransaction transaction) {\n\n    }\n    /**\n     * Execute transaction immediately without scheduling it. This is used for local requests, so\n     * it will also recycle the transaction.\n     */\n    public void executeTransaction(ClientTransaction transaction) {\n    }\n\n    /**\n     * Get the {@link TransactionExecutor} that will be performing lifecycle transitions and\n     * callbacks for activities.\n     */\n    abstract TransactionExecutor getTransactionExecutor();\n    abstract void sendMessage(int what, Object obj);\n    // Prepare phase related logic and handlers. Methods that inform about about pending changes or\n    // do other internal bookkeeping.\n    /** Set pending config in case it will be updated by other transaction item. */\n    public abstract void updatePendingConfiguration(Configuration config);\n    /** Set current process state. */\n    public abstract void updateProcessState(int processState, boolean fromIpc);\n    // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions\n    // and deliver callbacks.\n    /** Destroy the activity. */\n    public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,\n            boolean getNonConfigInstance, String reason);\n    /** Pause the activity. */\n    public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,\n            int configChanges, PendingTransactionActions pendingActions, String reason);\n\n    // Android 12\n    /** Destroy the activity. */\n    public abstract void handleDestroyActivity(ActivityThread.ActivityClientRecord r, boolean finishing,\n                                               int configChanges, boolean getNonConfigInstance, String reason);\n\n    /** Pause the activity. */\n    public abstract void handlePauseActivity(ActivityThread.ActivityClientRecord r, boolean finished, boolean userLeaving,\n                                             int configChanges, PendingTransactionActions pendingActions, String reason);\n    /**\n     * Resume the activity.\n     * @param token Target activity token.\n     * @param finalStateRequest Flag indicating if this call is handling final lifecycle state\n     *                          request for a transaction.\n     * @param isForward Flag indicating if next transition is forward.\n     * @param reason Reason for performing this operation.\n     */\n    public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,\n            boolean isForward, String reason);\n\n    // Android 12\n    public abstract void handleResumeActivity(ActivityThread.ActivityClientRecord record, boolean finalStateRequest,\n                                              boolean isForward, String reason);\n\n    /**\n     * Stop the activity.\n     * @param token Target activity token.\n     * @param show Flag indicating whether activity is still shown.\n     * @param configChanges Activity configuration changes.\n     * @param pendingActions Pending actions to be used on this or later stages of activity\n     *                       transaction.\n     * @param finalStateRequest Flag indicating if this call is handling final lifecycle state\n     *                          request for a transaction.\n     * @param reason Reason for performing this operation.\n     */\n    public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,\n            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);\n\n    // Android 11\n    public abstract void handleStopActivity(IBinder token, int configChanges,\n                                            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);\n\n    // Android 12\n    public abstract void handleStopActivity(ActivityThread.ActivityClientRecord r, int configChanges,\n                                            PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);\n\n    /** Report that activity was stopped to server. */\n    public abstract void reportStop(PendingTransactionActions pendingActions);\n    /** Restart the activity after it was stopped. */\n    public abstract void performRestartActivity(IBinder token, boolean start);\n    /** Restart the activity after it was stopped. */\n    public abstract void performRestartActivity(ActivityThread.ActivityClientRecord r, boolean start);\n\n    /** Deliver activity (override) configuration change. */\n    public abstract void handleActivityConfigurationChanged(IBinder activityToken,\n            Configuration overrideConfig, int displayId);\n    public abstract void handleActivityConfigurationChanged(ActivityThread.ActivityClientRecord r,\n                                                            Configuration overrideConfig, int displayId);\n\n    /** Deliver result from another activity. */\n    public abstract void handleSendResult(IBinder token, List results, String reason);\n\n    /** Deliver result from another activity. */\n    public abstract void handleSendResult(\n            ActivityThread.ActivityClientRecord r, List results, String reason);\n\n    /** Deliver multi-window mode change notification. */\n    public abstract void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,\n            Configuration overrideConfig);\n    /** Deliver new intent. */\n    public abstract void handleNewIntent(IBinder token, List intents,\n            boolean andPause);\n    public abstract void handleNewIntent(\n            ActivityThread.ActivityClientRecord r, List<ReferrerIntent> intents);\n    /** Deliver picture-in-picture mode change notification. */\n    public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,\n            Configuration overrideConfig);\n\n    // Android 11\n    public abstract void handlePictureInPictureRequested(IBinder token);\n    public abstract void handlePictureInPictureRequested(ActivityThread.ActivityClientRecord r);\n\n    /** Signal to an activity (that is currently in PiP) of PiP state changes. */\n    public abstract void handlePictureInPictureStateChanged(ActivityThread.ActivityClientRecord r,\n                                                            Parcelable pipState);\n\n    /** Whether the activity want to handle splash screen exit animation */\n    public abstract boolean isHandleSplashScreenExit(IBinder token);\n\n    /** Attach a splash screen window view to the top of the activity */\n    public abstract void handleAttachSplashScreenView(ActivityThread.ActivityClientRecord r,\n                                                      Parcelable parcelable);\n\n    /** Hand over the splash screen window view to the activity */\n    public abstract void handOverSplashScreenView(ActivityThread.ActivityClientRecord r);\n\n    /** Update window visibility. */\n    public abstract void handleWindowVisibility(IBinder token, boolean show);\n    /** Perform activity launch. */\n    public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r,\n            PendingTransactionActions pendingActions, Intent customIntent);\n    /** Perform activity start. */\n    public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r,\n            PendingTransactionActions pendingActions);\n\n    // Android 12\n    /** Perform activity start. */\n    public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r,\n                                             PendingTransactionActions pendingActions, ActivityOptions options);\n\n    // Android 11\n    public abstract void handleStartActivity(IBinder binder,\n                                             PendingTransactionActions pendingActions);\n    /** Get package info. */\n    public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,\n                                                    CompatibilityInfo compatInfo);\n    /** Deliver app configuration change notification. */\n    public abstract void handleConfigurationChanged(Configuration config);\n\n    public abstract void handleFixedRotationAdjustments(IBinder token,\n                                                        DisplayAdjustments.FixedRotationAdjustments fixedRotationAdjustments);\n\n    /**\n     * Add {@link ActivityThread.ActivityClientRecord} that is preparing to be launched.\n     * @param token Activity token.\n     * @param activity An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during launch.\n     */\n    public abstract void addLaunchingActivity(IBinder token, ActivityThread.ActivityClientRecord activity);\n\n    /**\n     * Get {@link ActivityThread.ActivityClientRecord} that is preparing to be launched.\n     * @param token Activity token.\n     * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during launch.\n     */\n    public abstract ActivityThread.ActivityClientRecord getLaunchingActivity(IBinder token);\n\n    /**\n     * Remove {@link ActivityThread.ActivityClientRecord} from the launching activity list.\n     * @param token Activity token.\n     */\n    public abstract void removeLaunchingActivity(IBinder token);\n\n    /**\n     * Get {@link ActivityThread.ActivityClientRecord} instance that corresponds to the\n     * provided token.\n     */\n    public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);\n    /**\n     * Prepare activity relaunch to update internal bookkeeping. This is used to track multiple\n     * relaunch and config update requests.\n     * @param token Activity token.\n     * @param pendingResults Activity results to be delivered.\n     * @param pendingNewIntents New intent messages to be delivered.\n     * @param configChanges Mask of configuration changes that have occurred.\n     * @param config New configuration applied to the activity.\n     * @param preserveWindow Whether the activity should try to reuse the window it created,\n     *                        including the decor view after the relaunch.\n     * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during\n     *         relaunch, or {@code null} if relaunch cancelled.\n     */\n    public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token,\n            List pendingResults, List pendingNewIntents,\n            int configChanges, MergedConfiguration config, boolean preserveWindow);\n    /**\n     * Perform activity relaunch.\n     * @param r Activity client record prepared for relaunch.\n     * @param pendingActions Pending actions to be used on later stages of activity transaction.\n     * */\n    public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r,\n            PendingTransactionActions pendingActions);\n    /**\n     * Report that relaunch request was handled.\n     * @param token Target activity token.\n     * @param pendingActions Pending actions initialized on earlier stages of activity transaction.\n     *                       Used to check if we should report relaunch to WM.\n     * */\n    public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions);\n\n    public abstract Map getActivitiesToBeDestroyed();\n\n    // Android 10\n    public abstract Activity getActivity(IBinder token);\n\n    public abstract void updatePendingActivityConfiguration(IBinder arg1, Configuration arg2);\n\n    public abstract void handleTopResumedActivityChanged(IBinder arg1, boolean arg2, String arg3);\n\n    public abstract void handleTopResumedActivityChanged(ActivityThread.ActivityClientRecord record, boolean arg2, String arg3);\n\n\n    /** Count how many activities are launching. */\n    public abstract void countLaunchingActivities(int num);\n\n    /** Deliver new intent. */\n    public abstract void handleNewIntent(IBinder token, List intents);\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/LoadedApk.java",
    "content": "package android.app;\n\n/**\n * @author weishu\n * @date 2018/8/7.\n */\npublic class LoadedApk {\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/TransactionHandlerProxy.java",
    "content": "package android.app;\n\nimport android.app.ActivityThread.ActivityClientRecord;\nimport android.app.servertransaction.PendingTransactionActions;\nimport android.app.servertransaction.TransactionExecutor;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.res.CompatibilityInfo;\nimport android.content.res.Configuration;\nimport android.os.IBinder;\nimport android.os.Parcelable;\nimport android.util.Log;\nimport android.util.MergedConfiguration;\nimport android.view.DisplayAdjustments;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.remote.StubActivityRecord;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.android.app.ActivityManagerNative;\nimport mirror.android.app.IActivityManager;\nimport mirror.com.android.internal.content.ReferrerIntent;\n\n\n/**\n * @author weishu\n * @date 2018/8/7.\n */\npublic class TransactionHandlerProxy extends ClientTransactionHandler {\n\n    private static final String TAG = \"TransactionHandlerProxy\";\n\n    private ClientTransactionHandler originalHandler;\n\n    public TransactionHandlerProxy(ClientTransactionHandler originalHandler) {\n        this.originalHandler = originalHandler;\n    }\n\n    @Override\n    TransactionExecutor getTransactionExecutor() {\n        return originalHandler.getTransactionExecutor();\n    }\n\n    @Override\n    void sendMessage(int what, Object obj) {\n        originalHandler.sendMessage(what, obj);\n    }\n\n    @Override\n    public void updatePendingConfiguration(Configuration config) {\n        originalHandler.updatePendingConfiguration(config);\n    }\n\n    @Override\n    public void updateProcessState(int processState, boolean fromIpc) {\n        originalHandler.updateProcessState(processState, fromIpc);\n    }\n\n    @Override\n    public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {\n        originalHandler.handleDestroyActivity(token, finishing, configChanges, getNonConfigInstance, reason);\n    }\n\n    @Override\n    public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) {\n        originalHandler.handlePauseActivity(token, finished, userLeaving, configChanges, pendingActions, reason);\n    }\n\n    @Override\n    public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {\n        originalHandler.handleDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);\n    }\n\n    @Override\n    public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) {\n        originalHandler.handlePauseActivity(r, finished, userLeaving, configChanges, pendingActions, reason);\n    }\n\n    @Override\n    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {\n        originalHandler.handleResumeActivity(token, finalStateRequest, isForward, reason);\n    }\n\n    @Override\n    public void handleResumeActivity(ActivityClientRecord record, boolean finalStateRequest, boolean isForward, String reason) {\n        originalHandler.handleResumeActivity(record, finalStateRequest, isForward, reason);\n    }\n\n    @Override\n    public void handleStopActivity(IBinder token, boolean show, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {\n        originalHandler.handleStopActivity(token, show, configChanges, pendingActions, finalStateRequest, reason);\n    }\n\n    @Override\n    public void handleStopActivity(IBinder token, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {\n        originalHandler.handleStopActivity(token, configChanges, pendingActions, finalStateRequest, reason);\n    }\n\n    @Override\n    public void handleStopActivity(ActivityClientRecord r, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {\n        originalHandler.handleStopActivity(r, configChanges, pendingActions, finalStateRequest, reason);\n    }\n\n    @Override\n    public void reportStop(PendingTransactionActions pendingActions) {\n        originalHandler.reportStop(pendingActions);\n    }\n\n    @Override\n    public void performRestartActivity(IBinder token, boolean start) {\n        originalHandler.performRestartActivity(token, start);\n    }\n\n    @Override\n    public void performRestartActivity(ActivityClientRecord r, boolean start) {\n        originalHandler.performRestartActivity(r, start);\n    }\n\n    @Override\n    public void handleActivityConfigurationChanged(IBinder activityToken, Configuration overrideConfig, int displayId) {\n        originalHandler.handleActivityConfigurationChanged(activityToken, overrideConfig, displayId);\n    }\n\n    @Override\n    public void handleActivityConfigurationChanged(ActivityClientRecord r, Configuration overrideConfig, int displayId) {\n        originalHandler.handleActivityConfigurationChanged(r, overrideConfig, displayId);\n    }\n\n    @Override\n    public void handleSendResult(IBinder token, List results, String reason) {\n        originalHandler.handleSendResult(token, results, reason);\n    }\n\n    @Override\n    public void handleSendResult(ActivityClientRecord r, List results, String reason) {\n        originalHandler.handleSendResult(r, results, reason);\n    }\n\n    @Override\n    public void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, Configuration overrideConfig) {\n        originalHandler.handleMultiWindowModeChanged(token, isInMultiWindowMode, overrideConfig);\n    }\n\n    @Override\n    public void handleNewIntent(IBinder token, List intents, boolean andPause) {\n        originalHandler.handleNewIntent(token, intents, andPause);\n    }\n\n    @Override\n    public void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, Configuration overrideConfig) {\n        originalHandler.handlePictureInPictureModeChanged(token, isInPipMode, overrideConfig);\n    }\n\n    @Override\n    public void handlePictureInPictureRequested(IBinder token) {\n        originalHandler.handlePictureInPictureRequested(token);\n    }\n\n    @Override\n    public void handlePictureInPictureRequested(ActivityClientRecord r) {\n        originalHandler.handlePictureInPictureRequested(r);\n    }\n\n    @Override\n    public void handlePictureInPictureStateChanged(ActivityClientRecord r, Parcelable pipState) {\n        originalHandler.handlePictureInPictureStateChanged(r, pipState);\n    }\n\n    @Override\n    public boolean isHandleSplashScreenExit(IBinder token) {\n        return originalHandler.isHandleSplashScreenExit(token);\n    }\n\n    @Override\n    public void handleAttachSplashScreenView(ActivityClientRecord r, Parcelable parcelable) {\n        originalHandler.handleAttachSplashScreenView(r, parcelable);\n    }\n\n    @Override\n    public void handOverSplashScreenView(ActivityClientRecord r) {\n        originalHandler.handOverSplashScreenView(r);\n    }\n\n    @Override\n    public void handleWindowVisibility(IBinder token, boolean show) {\n        originalHandler.handleWindowVisibility(token, show);\n    }\n\n    @Override\n    public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {\n\n        Intent stubIntent = mirror.android.app.ActivityThread.ActivityClientRecord.intent.get(r);\n        StubActivityRecord saveInstance = new StubActivityRecord(stubIntent);\n        if (saveInstance.intent == null) {\n            Log.i(TAG, \"save instance intent is null, return\");\n            return null;\n        }\n        Intent intent = saveInstance.intent;\n        ComponentName caller = saveInstance.caller;\n        IBinder token = mirror.android.app.ActivityThread.ActivityClientRecord.token.get(r);\n        ActivityInfo info = saveInstance.info;\n        if (VClientImpl.get().getToken() == null) {\n            InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);\n            if (installedAppInfo == null) {\n                Log.i(TAG, \"install app info is null, return\");\n                return null;\n            }\n            VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId);\n            // getH().sendMessageAtFrontOfQueue(Message.obtain(msg));\n            Log.i(TAG, \"restart process, return\");\n            return handleLaunchActivity(r, pendingActions, customIntent);\n        }\n        if (!VClientImpl.get().isBound()) {\n            VClientImpl.get().bindApplicationForActivity(info.packageName, info.processName, intent);\n            // getH().sendMessageAtFrontOfQueue(Message.obtain(msg));\n            Log.i(TAG, \"rebound application, return\");\n            return handleLaunchActivity(r, pendingActions, customIntent);\n        }\n        int taskId = IActivityManager.getTaskForActivity.call(\n                ActivityManagerNative.getDefault.call(),\n                token,\n                false\n        );\n\n        Object packageInfo = mirror.android.app.ActivityThread.ActivityClientRecord.packageInfo.get(r);\n\n        mirror.android.app.ActivityThread.ActivityClientRecord.packageInfo.set(r, null);\n\n        VActivityManager.get().onActivityCreate(ComponentUtils.toComponentName(info), caller, token, info, intent, ComponentUtils.getTaskAffinity(info), taskId, info.launchMode, info.flags);\n        ClassLoader appClassLoader = VClientImpl.get().getClassLoader(info.applicationInfo);\n        intent.setExtrasClassLoader(appClassLoader);\n        mirror.android.app.ActivityThread.ActivityClientRecord.intent.set(r, intent);\n        mirror.android.app.ActivityThread.ActivityClientRecord.activityInfo.set(r, info);\n\n        return originalHandler.handleLaunchActivity(r, pendingActions, customIntent);\n    }\n\n    @Override\n    public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, ActivityOptions options) {\n        originalHandler.handleStartActivity(r, pendingActions, options);\n    }\n\n    @Override\n    public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) {\n        originalHandler.handleStartActivity(r, pendingActions);\n    }\n\n    @Override\n    public void handleStartActivity(IBinder binder, PendingTransactionActions pendingActions) {\n        originalHandler.handleStartActivity(binder, pendingActions);\n    }\n\n    @Override\n    public LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo) {\n        return originalHandler.getPackageInfoNoCheck(ai, compatInfo);\n    }\n\n    @Override\n    public void handleConfigurationChanged(Configuration config) {\n        originalHandler.handleConfigurationChanged(config);\n    }\n\n    @Override\n    public void handleFixedRotationAdjustments(IBinder token, DisplayAdjustments.FixedRotationAdjustments fixedRotationAdjustments) {\n        originalHandler.handleFixedRotationAdjustments(token, fixedRotationAdjustments);\n    }\n\n    @Override\n    public void addLaunchingActivity(IBinder token, ActivityClientRecord activity) {\n        originalHandler.addLaunchingActivity(token, activity);\n    }\n\n    @Override\n    public ActivityClientRecord getLaunchingActivity(IBinder token) {\n        return originalHandler.getLaunchingActivity(token);\n    }\n\n    @Override\n    public void removeLaunchingActivity(IBinder token) {\n        originalHandler.removeLaunchingActivity(token);\n    }\n\n    @Override\n    public ActivityClientRecord getActivityClient(IBinder token) {\n        Log.i(TAG, \"getActivityClient : \" + token);\n        return originalHandler.getActivityClient(token);\n    }\n\n    @Override\n    public ActivityClientRecord prepareRelaunchActivity(IBinder token, List pendingResults, List pendingNewIntents, int configChanges, MergedConfiguration config, boolean preserveWindow) {\n        return originalHandler.prepareRelaunchActivity(token, pendingResults, pendingNewIntents, configChanges, config, preserveWindow);\n    }\n\n    @Override\n    public void handleRelaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) {\n        originalHandler.handleRelaunchActivity(r, pendingActions);\n    }\n\n    @Override\n    public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) {\n        originalHandler.reportRelaunch(token, pendingActions);\n    }\n\n    @Override\n    public Map getActivitiesToBeDestroyed() {\n        return originalHandler.getActivitiesToBeDestroyed();\n    }\n\n    @Override\n    public Activity getActivity(IBinder token) {\n        return originalHandler.getActivity(token);\n    }\n\n    @Override\n    public void updatePendingActivityConfiguration(IBinder arg1, Configuration arg2) {\n        originalHandler.updatePendingActivityConfiguration(arg1, arg2);\n    }\n\n    @Override\n    public void handleTopResumedActivityChanged(IBinder arg1, boolean arg2, String arg3) {\n        originalHandler.handleTopResumedActivityChanged(arg1, arg2, arg3);\n    }\n\n    @Override\n    public void handleTopResumedActivityChanged(ActivityClientRecord record, boolean arg2, String arg3) {\n        originalHandler.handleTopResumedActivityChanged(record, arg2, arg3);\n    }\n\n    @Override\n    public void countLaunchingActivities(int num) {\n        originalHandler.countLaunchingActivities(num);\n    }\n\n    @Override\n    public void handleNewIntent(IBinder token, List intents) {\n        originalHandler.handleNewIntent(token, intents);\n    }\n\n    @Override\n    public void handleNewIntent(ActivityClientRecord r, List<ReferrerIntent> intents) {\n        originalHandler.handleNewIntent(r, intents);\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/servertransaction/ClientTransaction.java",
    "content": "/*\n * Copyright 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage android.app.servertransaction;\n/**\n * A container that holds a sequence of messages, which may be sent to a client.\n * This includes a list of callbacks and a final lifecycle state.\n *\n * @see com.android.server.am.ClientLifecycleManager\n * @see ClientTransactionItem\n * @see ActivityLifecycleItem\n * @hide\n */\npublic class ClientTransaction {\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/servertransaction/PendingTransactionActions.java",
    "content": "/*\n * Copyright 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage android.app.servertransaction;\n/**\n * Container that has data pending to be used at later stages of\n * {@link ClientTransaction}.\n * An instance of this class is passed to each individual transaction item, so it can use some\n * information from previous steps or add some for the following steps.\n *\n * @hide\n */\npublic class PendingTransactionActions {\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/app/servertransaction/TransactionExecutor.java",
    "content": "/*\n * Copyright 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage android.app.servertransaction;\n\n/**\n * Class that manages transaction execution in the correct order.\n * @hide\n */\npublic class TransactionExecutor {\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/content/SyncStatusInfo.java",
    "content": "package android.content;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Log;\n\nimport java.util.ArrayList;\n\npublic class SyncStatusInfo implements Parcelable {\n    static final int VERSION = 2;\n\n    public final int authorityId;\n    public long totalElapsedTime;\n    public int numSyncs;\n    public int numSourcePoll;\n    public int numSourceServer;\n    public int numSourceLocal;\n    public int numSourceUser;\n    public int numSourcePeriodic;\n    public long lastSuccessTime;\n    public int lastSuccessSource;\n    public long lastFailureTime;\n    public int lastFailureSource;\n    public String lastFailureMesg;\n    public long initialFailureTime;\n    public boolean pending;\n    public boolean initialize;\n    \n  // Warning: It is up to the external caller to ensure there are\n  // no race conditions when accessing this list\n  private ArrayList<Long> periodicSyncTimes;\n\n    private static final String TAG = \"Sync\";\n\n    public SyncStatusInfo(int authorityId) {\n        this.authorityId = authorityId;\n    }\n\n    public int getLastFailureMesgAsInt(int def) {\n        return 0;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel parcel, int flags) {\n        parcel.writeInt(VERSION);\n        parcel.writeInt(authorityId);\n        parcel.writeLong(totalElapsedTime);\n        parcel.writeInt(numSyncs);\n        parcel.writeInt(numSourcePoll);\n        parcel.writeInt(numSourceServer);\n        parcel.writeInt(numSourceLocal);\n        parcel.writeInt(numSourceUser);\n        parcel.writeLong(lastSuccessTime);\n        parcel.writeInt(lastSuccessSource);\n        parcel.writeLong(lastFailureTime);\n        parcel.writeInt(lastFailureSource);\n        parcel.writeString(lastFailureMesg);\n        parcel.writeLong(initialFailureTime);\n        parcel.writeInt(pending ? 1 : 0);\n        parcel.writeInt(initialize ? 1 : 0);\n        if (periodicSyncTimes != null) {\n            parcel.writeInt(periodicSyncTimes.size());\n            for (long periodicSyncTime : periodicSyncTimes) {\n                parcel.writeLong(periodicSyncTime);\n            }\n        } else {\n            parcel.writeInt(-1);\n        }\n    }\n\n    public SyncStatusInfo(Parcel parcel) {\n        int version = parcel.readInt();\n        if (version != VERSION && version != 1) {\n            Log.w(\"SyncStatusInfo\", \"Unknown version: \" + version);\n        }\n        authorityId = parcel.readInt();\n        totalElapsedTime = parcel.readLong();\n        numSyncs = parcel.readInt();\n        numSourcePoll = parcel.readInt();\n        numSourceServer = parcel.readInt();\n        numSourceLocal = parcel.readInt();\n        numSourceUser = parcel.readInt();\n        lastSuccessTime = parcel.readLong();\n        lastSuccessSource = parcel.readInt();\n        lastFailureTime = parcel.readLong();\n        lastFailureSource = parcel.readInt();\n        lastFailureMesg = parcel.readString();\n        initialFailureTime = parcel.readLong();\n        pending = parcel.readInt() != 0;\n        initialize = parcel.readInt() != 0;\n        if (version == 1) {\n            periodicSyncTimes = null;\n        } else {\n            int N = parcel.readInt();\n            if (N < 0) {\n                periodicSyncTimes = null;\n            } else {\n                periodicSyncTimes = new ArrayList<Long>();\n                for (int i=0; i<N; i++) {\n                    periodicSyncTimes.add(parcel.readLong());\n                }\n            }\n        }\n    }\n\n    public SyncStatusInfo(SyncStatusInfo other) {\n        authorityId = other.authorityId;\n        totalElapsedTime = other.totalElapsedTime;\n        numSyncs = other.numSyncs;\n        numSourcePoll = other.numSourcePoll;\n        numSourceServer = other.numSourceServer;\n        numSourceLocal = other.numSourceLocal;\n        numSourceUser = other.numSourceUser;\n        numSourcePeriodic = other.numSourcePeriodic;\n        lastSuccessTime = other.lastSuccessTime;\n        lastSuccessSource = other.lastSuccessSource;\n        lastFailureTime = other.lastFailureTime;\n        lastFailureSource = other.lastFailureSource;\n        lastFailureMesg = other.lastFailureMesg;\n        initialFailureTime = other.initialFailureTime;\n        pending = other.pending;\n        initialize = other.initialize;\n        if (other.periodicSyncTimes != null) {\n            periodicSyncTimes = new ArrayList<Long>(other.periodicSyncTimes);\n        }\n    }\n\n    public void setPeriodicSyncTime(int index, long when) {\n        // The list is initialized lazily when scheduling occurs so we need to make sure\n        // we initialize elements < index to zero (zero is ignore for scheduling purposes)\n        ensurePeriodicSyncTimeSize(index);\n        periodicSyncTimes.set(index, when);\n    }\n\n    public long getPeriodicSyncTime(int index) {\n        if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {\n            return periodicSyncTimes.get(index);\n        } else {\n            return 0;\n        }\n    }\n\n    public void removePeriodicSyncTime(int index) {\n        if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {\n            periodicSyncTimes.remove(index);\n        }\n    }\n\n    public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {\n        public SyncStatusInfo createFromParcel(Parcel in) {\n            return new SyncStatusInfo(in);\n        }\n\n        public SyncStatusInfo[] newArray(int size) {\n            return new SyncStatusInfo[size];\n        }\n    };\n\n    private void ensurePeriodicSyncTimeSize(int index) {\n        if (periodicSyncTimes == null) {\n            periodicSyncTimes = new ArrayList<>(0);\n        }\n\n        final int requiredSize = index + 1;\n        if (periodicSyncTimes.size() < requiredSize) {\n            for (int i = periodicSyncTimes.size(); i < requiredSize; i++) {\n                periodicSyncTimes.add((long) 0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/content/pm/PackageParser.java",
    "content": "package android.content.pm;\n\nimport android.content.ComponentName;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\n\nimport java.util.ArrayList;\n\n/**\n * @author Lody\n */\npublic class PackageParser {\n\n    public static final int PARSE_IS_SYSTEM = 1;\n\n    public static class IntentInfo extends IntentFilter {\n        public boolean hasDefault;\n        public int labelRes;\n        public CharSequence nonLocalizedLabel;\n        public int icon;\n        public int logo;\n        public int banner;\n    }\n\n    public static class Component<II extends IntentInfo> {\n        public Package owner;\n        public ArrayList<II> intents;\n        public String className;\n        public Bundle metaData;\n\n        public ComponentName getComponentName() {\n            return null;\n        }\n    }\n\n    public final static class Activity extends Component<ActivityIntentInfo> {\n        public ActivityInfo info;\n    }\n\n    public class Package {\n        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);\n        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);\n        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);\n        public final ArrayList<Service> services = new ArrayList<Service>(0);\n        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);\n        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);\n        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);\n        public final ArrayList<String> requestedPermissions = new ArrayList<String>();\n        public Signature[] mSignatures;\n        public Bundle mAppMetaData;\n        public Object mExtras;\n        public String packageName;\n        public int mPreferredOrder;\n        public String mSharedUserId;\n        public ArrayList<String> usesLibraries;\n        public int mVersionCode;\n        public ApplicationInfo applicationInfo;\n        public String mVersionName;\n\n        // Applications hardware preferences\n        public ArrayList<ConfigurationInfo> configPreferences = null;\n\n        // Applications requested features\n        public ArrayList<FeatureInfo> reqFeatures = null;\n        public int mSharedUserLabel;\n\n        public String[] splitNames;\n        public String codePath;\n        public String baseCodePath;\n        public String[] splitCodePaths;\n\n        public ArrayList<String> usesOptionalLibraries;\n    }\n\n    public final class Service extends Component<ServiceIntentInfo> {\n        public ServiceInfo info;\n    }\n\n    public final class Provider extends Component<ProviderIntentInfo> {\n        public ProviderInfo info;\n    }\n\n    public final class Instrumentation extends Component<IntentInfo> {\n        public InstrumentationInfo info;\n    }\n\n    public final class Permission extends Component<IntentInfo> {\n        public PermissionInfo info;\n    }\n\n    public final class PermissionGroup extends Component<IntentInfo> {\n        public PermissionGroupInfo info;\n    }\n\n    public class ActivityIntentInfo extends IntentInfo {\n        public Activity activity;\n    }\n\n\n    public class ServiceIntentInfo extends IntentInfo {\n        public Service service;\n    }\n\n    public class ProviderIntentInfo extends IntentInfo {\n        public Provider provider;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/content/res/CompatibilityInfo.java",
    "content": "\n/*\n * Copyright (C) 2006 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage android.content.res;\n/**\n * CompatibilityInfo class keeps the information about compatibility mode that the application is\n * running under.\n * \n *  {@hide} \n */\npublic class CompatibilityInfo {\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/location/LocationRequest.java",
    "content": "package android.location;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic final class LocationRequest implements Parcelable {\n\n    public String getProvider() {\n        return null;\n    }\n\n\n    public static final Creator<LocationRequest> CREATOR = new Creator<LocationRequest>() {\n        @Override\n        public LocationRequest createFromParcel(Parcel in) {\n            return null;\n        }\n\n        @Override\n        public LocationRequest[] newArray(int size) {\n            return null;\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/util/MergedConfiguration.java",
    "content": "/*\n * Copyright (C) 2017 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License\n */\npackage android.util;\n/**\n * Container that holds global and override config and their merge product.\n * Merged configuration updates automatically whenever global or override configs are updated via\n * setters.\n *\n * {@hide}\n */\npublic class MergedConfiguration {\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/android/view/DisplayAdjustments.java",
    "content": "package android.view;\n\n/**\n * @author weishu\n * @date 2020/11/23.\n */\n\n// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/DisplayAdjustments.java;drc=master;l=184\npublic class DisplayAdjustments {\n    public static class FixedRotationAdjustments {}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/Build.java",
    "content": "package com.lody.virtual;\n\n/**\n *\n * Version info of VirtualApp project.\n *\n * @author Lody\n *\n */\n\npublic class Build {\n\n    public static final String VERSION_NAME = \"Build-823-01\";\n\n    public static final int VERSION_CODE = 8230001;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/DelegateApplication64Bit.java",
    "content": "package com.lody.virtual;\n\nimport android.annotation.TargetApi;\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.res.Configuration;\nimport android.os.Build;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n\n/**\n * @author Lody\n *         <p>\n *         <p>\n *         Copy the file to your Project.\n */\n@TargetApi(Build.VERSION_CODES.M)\npublic abstract class DelegateApplication64Bit extends Application {\n\n    private Application mTarget;\n\n    protected abstract String get32BitPackageName();\n\n\n    private static Field findField(Object instance, String name) throws NoSuchFieldException {\n        for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {\n            try {\n                Field field = clazz.getDeclaredField(name);\n\n\n                if (!field.isAccessible()) {\n                    field.setAccessible(true);\n                }\n\n                return field;\n            } catch (NoSuchFieldException e) {\n                // ignore and search next\n            }\n        }\n\n        throw new NoSuchFieldException(\"Field \" + name + \" not found in \" + instance.getClass());\n    }\n\n\n    private static Method findMethod(Object instance, String name, Class<?>... parameterTypes)\n            throws NoSuchMethodException {\n        for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {\n            try {\n                Method method = clazz.getDeclaredMethod(name, parameterTypes);\n\n\n                if (!method.isAccessible()) {\n                    method.setAccessible(true);\n                }\n\n                return method;\n            } catch (NoSuchMethodException e) {\n                // ignore and search next\n            }\n        }\n\n        throw new NoSuchMethodException(\"Method \" + name + \" with parameters \" +\n                Arrays.asList(parameterTypes) + \" not found in \" + instance.getClass());\n    }\n\n\n    private static void expandFieldArray(Object instance, String fieldName,\n                                         Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException,\n            IllegalAccessException {\n        Field jlrField = findField(instance, fieldName);\n        Object[] original = (Object[]) jlrField.get(instance);\n        Object[] combined = (Object[]) Array.newInstance(\n                original.getClass().getComponentType(), original.length + extraElements.length);\n        System.arraycopy(original, 0, combined, 0, original.length);\n        System.arraycopy(extraElements, 0, combined, original.length, extraElements.length);\n        jlrField.set(instance, combined);\n    }\n\n\n    private static void expandFieldList(Object instance, String fieldName, Object[] extraElements) throws NoSuchFieldException, IllegalAccessException {\n        Field field = findField(instance, fieldName);\n        Object[] original = ((List) field.get(instance)).toArray();\n        Object[] combined = (Object[]) Array.newInstance(original.getClass().getComponentType(), original.length + 1);\n        System.arraycopy(original, 0, combined, 0, original.length);\n        System.arraycopy(extraElements, 0, combined, original.length, 1);\n        field.set(instance, Arrays.asList(combined));\n    }\n\n    private static Object[] makeDexElements(\n            Object dexPathList, ArrayList<File> files,\n            ArrayList<IOException> suppressedExceptions)\n            throws IllegalAccessException, InvocationTargetException,\n            NoSuchMethodException {\n        Method makeDexElements;\n        if (Build.VERSION.SDK_INT >= 23) {\n            makeDexElements = findMethod(dexPathList, \"makePathElements\", List.class, File.class, List.class);\n        } else {\n            makeDexElements = findMethod(dexPathList, \"makeDexElements\", ArrayList.class, File.class, ArrayList.class);\n        }\n        return (Object[]) makeDexElements.invoke(dexPathList, files, null,\n                suppressedExceptions);\n\n    }\n\n    protected void attachBaseContext(Context context) {\n        super.attachBaseContext(context);\n        try {\n            ApplicationInfo ai = getPackageManager().getApplicationInfo(get32BitPackageName(), 0);\n            ClassLoader classLoader = getClassLoader();\n            Object dexPathList = findField(classLoader, \"pathList\").get(classLoader);\n            ArrayList<IOException> suppressedExceptions = new ArrayList<>();\n            ArrayList<File> dexFiles = new ArrayList<>();\n            dexFiles.add(new File(ai.publicSourceDir));\n            ArrayList<File> nativeLibs = new ArrayList<>();\n            nativeLibs.add(new File(ai.nativeLibraryDir));\n            if (Build.VERSION.SDK_INT > 25) {\n                expandFieldList(dexPathList, \"nativeLibraryDirectories\", new File[]{new File(ai.nativeLibraryDir)});\n                expandFieldArray(dexPathList, \"nativeLibraryPathElements\",\n                        (Object[]) findMethod(dexPathList, \"makePathElements\", List.class).invoke(dexPathList, nativeLibs));\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                expandFieldList(dexPathList, \"nativeLibraryDirectories\", new File[]{new File(ai.nativeLibraryDir)});\n                expandFieldArray(dexPathList, \"nativeLibraryPathElements\", makeDexElements(dexPathList, nativeLibs, suppressedExceptions));\n            } else {\n                expandFieldArray(dexPathList, \"nativeLibraryDirectories\", new File[]{new File(ai.nativeLibraryDir)});\n            }\n            expandFieldArray(dexPathList, \"dexElements\", makeDexElements(dexPathList, dexFiles, suppressedExceptions));\n            if (suppressedExceptions.size() > 0) {\n                for (IOException e : suppressedExceptions) {\n                    Log.w(getClass().getSimpleName(), \"Exception in makeDexElement\", e);\n                }\n                Field suppressedExceptionsField =\n                        findField(classLoader, \"dexElementsSuppressedExceptions\");\n                IOException[] dexElementsSuppressedExceptions =\n                        (IOException[]) suppressedExceptionsField.get(classLoader);\n\n                if (dexElementsSuppressedExceptions == null) {\n                    dexElementsSuppressedExceptions =\n                            suppressedExceptions.toArray(\n                                    new IOException[suppressedExceptions.size()]);\n                } else {\n                    IOException[] combined =\n                            new IOException[suppressedExceptions.size() +\n                                    dexElementsSuppressedExceptions.length];\n                    suppressedExceptions.toArray(combined);\n                    System.arraycopy(dexElementsSuppressedExceptions, 0, combined,\n                            suppressedExceptions.size(), dexElementsSuppressedExceptions.length);\n                    dexElementsSuppressedExceptions = combined;\n                }\n                suppressedExceptionsField.set(classLoader, dexElementsSuppressedExceptions);\n            }\n            mTarget = (Application) classLoader.loadClass(ai.className).newInstance();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    public void onConfigurationChanged(Configuration configuration) {\n        super.onConfigurationChanged(configuration);\n        if (mTarget != null) {\n            mTarget.onConfigurationChanged(configuration);\n        }\n    }\n\n    public void onCreate() {\n        super.onCreate();\n        if (mTarget != null) {\n            mTarget.onCreate();\n        }\n    }\n\n    public void onLowMemory() {\n        super.onLowMemory();\n        if (mTarget != null) {\n            mTarget.onLowMemory();\n        }\n    }\n\n    public void onTerminate() {\n        super.onTerminate();\n        if (mTarget != null) {\n            mTarget.onTerminate();\n        }\n    }\n\n    public void onTrimMemory(int i) {\n        super.onTrimMemory(i);\n        if (mTarget != null) {\n            mTarget.onTrimMemory(i);\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/GmsSupport.java",
    "content": "package com.lody.virtual;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * @author Lody\n */\npublic class GmsSupport {\n\n    public static final List<String> GOOGLE_APP = Arrays.asList(\n            \"com.android.vending\",\n            \"com.google.android.play.games\",\n            \"com.google.android.wearable.app\",\n            \"com.google.android.wearable.app.cn\"\n    );\n\n    public static final List<String> GOOGLE_SERVICE = Arrays.asList(\n            \"com.google.android.gsf\",\n            \"com.google.android.gms\",\n            \"com.google.android.gsf.login\",\n            \"com.google.android.backuptransport\",\n            \"com.google.android.backup\",\n            \"com.google.android.configupdater\",\n            \"com.google.android.syncadapters.contacts\",\n            \"com.google.android.feedback\",\n            \"com.google.android.onetimeinitializer\",\n            \"com.google.android.partnersetup\",\n            \"com.google.android.setupwizard\",\n            \"com.google.android.syncadapters.calendar\"\n    );\n\n    public static boolean isGmsFamilyPackage(String packageName) {\n        return packageName.equals(\"com.android.vending\")\n                || packageName.equals(\"com.google.android.gms\");\n    }\n\n    public static boolean isGoogleFrameworkInstalled() {\n        return VirtualCore.get().isAppInstalled(\"com.google.android.gms\");\n    }\n\n    public static boolean isOutsideGoogleFrameworkExist() {\n        return VirtualCore.get().isOutsideInstalled(\"com.google.android.gms\");\n    }\n\n    private static void installPackages(List<String> list, int userId) {\n        VirtualCore core = VirtualCore.get();\n        for (String packageName : list) {\n            if (core.isAppInstalledAsUser(userId, packageName)) {\n                continue;\n            }\n            ApplicationInfo info = null;\n            try {\n                info = VirtualCore.get().getUnHookPackageManager().getApplicationInfo(packageName, 0);\n            } catch (PackageManager.NameNotFoundException e) {\n                // Ignore\n            }\n            if (info == null || info.sourceDir == null) {\n                continue;\n            }\n            if (userId == 0) {\n                core.installPackage(info.sourceDir, InstallStrategy.DEPEND_SYSTEM_IF_EXIST);\n            } else {\n                core.installPackageAsUser(userId, packageName);\n            }\n        }\n    }\n\n    public static void installGApps(int userId) {\n        installPackages(GOOGLE_SERVICE, userId);\n        installPackages(GOOGLE_APP, userId);\n    }\n\n    public static void installGoogleService(int userId) {\n        installPackages(GOOGLE_SERVICE, userId);\n    }\n\n    public static void installGoogleApp(int userId) {\n        installPackages(GOOGLE_APP, userId);\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/NativeEngine.java",
    "content": "package com.lody.virtual.client;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Process;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.natives.NativeMethods;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.utils.DeviceUtil;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstalledAppInfo;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * VirtualApp Native Project\n */\npublic class NativeEngine {\n    private static final String TAG = NativeEngine.class.getSimpleName();\n\n    private static final String VESCAPE = \"/6decacfa7aad11e8a718985aebe4663a\";\n\n    private static Map<String, InstalledAppInfo> sDexOverrideMap;\n\n    private static boolean sFlag = false;\n\n    private static final String LIB_NAME = \"va++\";\n\n    static {\n        try {\n            System.loadLibrary(LIB_NAME);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    static {\n        NativeMethods.init();\n    }\n\n\n    public static void startDexOverride() {\n        List<InstalledAppInfo> installedAppInfos = VirtualCore.get().getInstalledApps(0);\n        sDexOverrideMap = new HashMap<>(installedAppInfos.size());\n        for (InstalledAppInfo info : installedAppInfos) {\n            try {\n                sDexOverrideMap.put(new File(info.apkPath).getCanonicalPath(), info);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static String getRedirectedPath(String redirectPath) {\n        try {\n            return nativeGetRedirectedPath(redirectPath);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n        return redirectPath;\n    }\n\n    public static String resverseRedirectedPath(String origPath) {\n        try {\n            return nativeReverseRedirectedPath(origPath);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n        return origPath;\n    }\n\n    public static void redirectDirectory(String origPath, String newPath) {\n        if (!origPath.endsWith(\"/\")) {\n            origPath = origPath + \"/\";\n        }\n        if (!newPath.endsWith(\"/\")) {\n            newPath = newPath + \"/\";\n        }\n        try {\n            nativeIORedirect(origPath, newPath);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    public static String getEscapePath(String path) {\n        if (path == null) {\n            return null;\n        }\n        File file = new File(path);\n        if (file.exists()) {\n            return file.getAbsolutePath();\n        }\n        return new File(VESCAPE, path).getAbsolutePath();\n    }\n\n    public static void redirectFile(String origPath, String newPath) {\n        if (origPath.endsWith(\"/\")) {\n            origPath = origPath.substring(0, origPath.length() - 1);\n        }\n        if (newPath.endsWith(\"/\")) {\n            newPath = newPath.substring(0, newPath.length() - 1);\n        }\n\n        try {\n            nativeIORedirect(origPath, newPath);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    public static void whitelist(String path, boolean directory) {\n        if (directory && !path.endsWith(\"/\")) {\n            path = path + \"/\";\n        } else if (!directory && path.endsWith(\"/\")) {\n            path = path.substring(0, path.length() - 1);\n        }\n        try {\n            nativeIOWhitelist(path);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    public static void forbid(String path) {\n        if (!path.endsWith(\"/\")) {\n            path = path + \"/\";\n        }\n        try {\n            nativeIOForbid(path);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    public static void enableIORedirect() {\n        try {\n            String soPath = VirtualCore.get().getContext().getApplicationInfo().nativeLibraryDir + File.separator + \"lib\" + LIB_NAME + \".so\";\n            if (!new File(soPath).exists()) {\n                throw new RuntimeException(\"io redirect failed.\");\n            }\n            redirectDirectory(VESCAPE, \"/\");\n            nativeEnableIORedirect(soPath, Build.VERSION.SDK_INT, BuildCompat.getPreviewSDKInt());\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n    }\n\n    static void launchEngine() {\n        if (sFlag) {\n            return;\n        }\n        Method[] methods = {NativeMethods.gOpenDexFileNative, NativeMethods.gCameraNativeSetup, NativeMethods.gAudioRecordNativeCheckPermission};\n        try {\n            nativeLaunchEngine(methods, VirtualCore.get().getHostPkg(), VirtualRuntime.isArt(), Build.VERSION.SDK_INT, NativeMethods.gCameraMethodType);\n        } catch (Throwable e) {\n            VLog.e(TAG, VLog.getStackTraceString(e));\n        }\n        sFlag = true;\n    }\n\n    public static void onKillProcess(int pid, int signal) {\n        VLog.e(TAG, \"killProcess: pid = %d, signal = %d.\", pid, signal);\n        if (pid == android.os.Process.myPid()) {\n            VLog.e(TAG, VLog.getStackTraceString(new Throwable()));\n        }\n    }\n\n    public static int onGetCallingUid(int originUid) {\n        int callingPid = Binder.getCallingPid();\n        if (callingPid == Process.myPid()) {\n            return VClientImpl.get().getBaseVUid();\n        }\n        if (callingPid == VirtualCore.get().getSystemPid()) {\n            return Process.SYSTEM_UID;\n        }\n        int vuid = VActivityManager.get().getUidByPid(callingPid);\n        if (vuid != -1) {\n            return VUserHandle.getAppId(vuid);\n        }\n        VLog.w(TAG, String.format(\"Unknown uid: %s\", callingPid));\n        return VClientImpl.get().getBaseVUid();\n    }\n\n    public static void onOpenDexFileNative(String[] params) {\n        String dexOrJarPath = params[0];\n        String outputPath = params[1];\n        VLog.d(TAG, \"DexOrJarPath = %s, OutputPath = %s.\", dexOrJarPath, outputPath);\n        try {\n            String canonical = new File(dexOrJarPath).getCanonicalPath();\n            InstalledAppInfo info = sDexOverrideMap.get(canonical);\n            if (info != null && !info.dependSystem || info != null && DeviceUtil.isMeizuBelowN() && params[1] == null) {\n                outputPath = info.getOdexFile().getPath();\n                params[1] = outputPath;\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    private static native void nativeLaunchEngine(Object[] method, String hostPackageName, boolean isArt, int apiLevel, int cameraMethodType);\n\n    private static native void nativeMark();\n\n    private static native String nativeReverseRedirectedPath(String redirectedPath);\n\n    private static native String nativeGetRedirectedPath(String orgPath);\n\n    private static native void nativeIORedirect(String origPath, String newPath);\n\n    private static native void nativeIOWhitelist(String path);\n\n    private static native void nativeIOForbid(String path);\n\n    private static native void nativeEnableIORedirect(String selfSoPath, int apiLevel, int previewApiLevel);\n\n    public static native void disableJit(int apiLevel);\n\n    public static int onGetUid(int uid) {\n        return VClientImpl.get().getBaseVUid();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java",
    "content": "package com.lody.virtual.client;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\nimport android.app.Instrumentation;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.ContentProviderClient;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.ConditionVariable;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.StrictMode;\nimport android.system.ErrnoException;\nimport android.system.Os;\n\nimport com.lody.virtual.client.core.CrashHandler;\nimport com.lody.virtual.client.core.InvocationStubManager;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.SpecialComponentList;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.fixer.ContextFixer;\nimport com.lody.virtual.client.hook.delegate.AppInstrumentation;\nimport com.lody.virtual.client.hook.providers.ProviderHook;\nimport com.lody.virtual.client.hook.proxies.am.HCallbackStub;\nimport com.lody.virtual.client.hook.secondary.ProxyServiceFactory;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.ipc.VDeviceManager;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.client.ipc.VirtualStorageManager;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.compat.StorageManagerCompat;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.remote.PendingResultData;\nimport com.lody.virtual.remote.VDeviceInfo;\nimport com.lody.virtual.server.interfaces.IUiCallback;\n\nimport java.io.File;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport dalvik.system.DelegateLastClassLoader;\nimport me.weishu.exposed.ExposedBridge;\nimport mirror.android.app.ActivityThread;\nimport mirror.android.app.ActivityThreadNMR1;\nimport mirror.android.app.ContextImpl;\nimport mirror.android.app.IActivityManager;\nimport mirror.android.app.LoadedApk;\nimport mirror.android.content.ContentProviderHolderOreo;\nimport mirror.android.providers.Settings;\nimport mirror.android.renderscript.RenderScriptCacheDir;\nimport mirror.android.security.net.config.ApplicationConfig;\nimport mirror.android.view.HardwareRenderer;\nimport mirror.android.view.RenderScript;\nimport mirror.android.view.ThreadedRenderer;\nimport mirror.com.android.internal.content.ReferrerIntent;\nimport mirror.dalvik.system.VMRuntime;\nimport mirror.java.lang.ThreadGroupN;\n\nimport static com.lody.virtual.os.VUserHandle.getUserId;\n\n/**\n * @author Lody\n */\n\npublic final class VClientImpl extends IVClient.Stub {\n\n    private static final int NEW_INTENT = 11;\n    private static final int RECEIVER = 12;\n\n    private static final String TAG = VClientImpl.class.getSimpleName();\n    @SuppressLint(\"StaticFieldLeak\")\n    private static final VClientImpl gClient = new VClientImpl();\n    private final H mH = new H();\n    private ConditionVariable mTempLock;\n    private Instrumentation mInstrumentation = AppInstrumentation.getDefault();\n    private IBinder token;\n    private int vuid;\n    private VDeviceInfo deviceInfo;\n    private AppBindData mBoundApplication;\n    private Application mInitialApplication;\n    private CrashHandler crashHandler;\n    private IUiCallback mUiCallback;\n\n    public static VClientImpl get() {\n        return gClient;\n    }\n\n    public boolean isBound() {\n        return mBoundApplication != null;\n    }\n\n    public VDeviceInfo getDeviceInfo() {\n        if (deviceInfo == null) {\n            synchronized (this) {\n                if (deviceInfo == null) {\n                    deviceInfo = VDeviceManager.get().getDeviceInfo(getUserId(vuid));\n                }\n            }\n        }\n        return deviceInfo;\n    }\n\n    public Application getCurrentApplication() {\n        return mInitialApplication;\n    }\n\n    public String getCurrentPackage() {\n        return mBoundApplication != null ?\n                mBoundApplication.appInfo.packageName : VPackageManager.get().getNameForUid(getVUid());\n    }\n\n    public ApplicationInfo getCurrentApplicationInfo() {\n        return mBoundApplication != null ? mBoundApplication.appInfo : null;\n    }\n\n    public CrashHandler getCrashHandler() {\n        return crashHandler;\n    }\n\n    public void setCrashHandler(CrashHandler crashHandler) {\n        this.crashHandler = crashHandler;\n    }\n\n    public int getVUid() {\n        return vuid;\n    }\n\n    public int getBaseVUid() {\n        return VUserHandle.getAppId(vuid);\n    }\n\n    public ClassLoader getClassLoader(ApplicationInfo appInfo) {\n        Context context = createPackageContext(appInfo.packageName);\n        return context.getClassLoader();\n    }\n\n    public ClassLoader getClassLoader(String packageName) {\n        Context context = createPackageContext(packageName);\n        return context.getClassLoader();\n    }\n\n    private void sendMessage(int what, Object obj) {\n        Message msg = Message.obtain();\n        msg.what = what;\n        msg.obj = obj;\n        mH.sendMessage(msg);\n    }\n\n    @Override\n    public IBinder getAppThread() {\n        return ActivityThread.getApplicationThread.call(VirtualCore.mainThread());\n    }\n\n    @Override\n    public IBinder getToken() {\n        return token;\n    }\n\n    public void initProcess(IBinder token, int vuid) {\n        this.token = token;\n        this.vuid = vuid;\n    }\n\n    private void handleNewIntent(NewIntentData data) {\n        Intent intent;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            intent = ReferrerIntent.ctor.newInstance(data.intent, data.creator);\n        } else {\n            intent = data.intent;\n        }\n        if (ActivityThread.performNewIntents != null) {\n            ActivityThread.performNewIntents.call(\n                    VirtualCore.mainThread(),\n                    data.token,\n                    Collections.singletonList(intent)\n            );\n        } else {\n            if (BuildCompat.isQ()) {\n                ActivityThread.handleNewIntent.call(VirtualCore.mainThread(), data.token, Collections.singletonList(intent));\n            } else {\n                ActivityThreadNMR1.performNewIntents.call(\n                        VirtualCore.mainThread(),\n                        data.token,\n                        Collections.singletonList(intent),\n                        true);\n            }\n        }\n    }\n\n    public void bindApplicationForActivity(final String packageName, final String processName, final Intent intent) {\n        mUiCallback = VirtualCore.getUiCallback(intent);\n        bindApplication(packageName, processName);\n    }\n\n    public void bindApplication(final String packageName, final String processName) {\n        if (Looper.getMainLooper() == Looper.myLooper()) {\n            bindApplicationNoCheck(packageName, processName, new ConditionVariable());\n        } else {\n            final ConditionVariable lock = new ConditionVariable();\n            VirtualRuntime.getUIHandler().post(new Runnable() {\n                @Override\n                public void run() {\n                    bindApplicationNoCheck(packageName, processName, lock);\n                    lock.open();\n                }\n            });\n            lock.block();\n        }\n    }\n\n    private void bindApplicationNoCheck(String packageName, String processName, ConditionVariable lock) {\n        VDeviceInfo deviceInfo = getDeviceInfo();\n        if (processName == null) {\n            processName = packageName;\n        }\n        mTempLock = lock;\n        try {\n            setupUncaughtHandler();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        try {\n            fixInstalledProviders();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        mirror.android.os.Build.SERIAL.set(deviceInfo.serial);\n        mirror.android.os.Build.DEVICE.set(Build.DEVICE.replace(\" \", \"_\"));\n        ActivityThread.mInitialApplication.set(\n                VirtualCore.mainThread(),\n                null\n        );\n        AppBindData data = new AppBindData();\n        InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0);\n        if (info == null) {\n            new Exception(\"App not exist!\").printStackTrace();\n            Process.killProcess(0);\n            System.exit(0);\n        }\n        data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid));\n        data.processName = processName;\n        data.appInfo.processName = processName;\n        data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA);\n        VLog.i(TAG, String.format(\"Binding application %s, (%s)\", data.appInfo.packageName, data.processName));\n        mBoundApplication = data;\n        VirtualRuntime.setupRuntime(data.processName, data.appInfo);\n        int targetSdkVersion = data.appInfo.targetSdkVersion;\n        if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {\n            StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();\n            StrictMode.setThreadPolicy(newPolicy);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {\n            mirror.android.os.Message.updateCheckRecycle.call(targetSdkVersion);\n        }\n        if (VASettings.ENABLE_IO_REDIRECT) {\n            startIOUniformer();\n        }\n        NativeEngine.launchEngine();\n        Object mainThread = VirtualCore.mainThread();\n        NativeEngine.startDexOverride();\n        Context context = createPackageContext(data.appInfo.packageName);\n        try {\n            // anti-virus, fuck ESET-NOD32: a variant of Android/AdDisplay.AdLock.AL potentially unwanted\n            // we can make direct call... use reflect to bypass.\n            // System.setProperty(\"java.io.tmpdir\", context.getCacheDir().getAbsolutePath());\n            System.class.getDeclaredMethod(\"setProperty\", String.class, String.class)\n                    .invoke(null, \"java.io.tmpdir\", context.getCacheDir().getAbsolutePath());\n        } catch (Throwable ignored) {\n            VLog.e(TAG, \"set tmp dir error:\", ignored);\n        }\n\n        File codeCacheDir;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            codeCacheDir = context.getCodeCacheDir();\n        } else {\n            codeCacheDir = context.getCacheDir();\n        }\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            if (HardwareRenderer.setupDiskCache != null) {\n                HardwareRenderer.setupDiskCache.call(codeCacheDir);\n            }\n        } else {\n            if (ThreadedRenderer.setupDiskCache != null) {\n                ThreadedRenderer.setupDiskCache.call(codeCacheDir);\n            }\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            if (RenderScriptCacheDir.setupDiskCache != null) {\n                RenderScriptCacheDir.setupDiskCache.call(codeCacheDir);\n            }\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            if (RenderScript.setupDiskCache != null) {\n                RenderScript.setupDiskCache.call(codeCacheDir);\n            }\n        }\n        Object boundApp = fixBoundApp(mBoundApplication);\n        mBoundApplication.info = ContextImpl.mPackageInfo.get(context);\n        mirror.android.app.ActivityThread.AppBindData.info.set(boundApp, data.info);\n        VMRuntime.setTargetSdkVersion.call(VMRuntime.getRuntime.call(), data.appInfo.targetSdkVersion);\n\n        boolean conflict = SpecialComponentList.ConflictInstrumentation.isConflictingInstrumentation(packageName);\n        if (!conflict) {\n            InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);\n        }\n\n        ApplicationInfo applicationInfo = LoadedApk.mApplicationInfo.get(data.info);\n        if (Build.VERSION.SDK_INT >= 26 && applicationInfo.splitNames == null) {\n            applicationInfo.splitNames = new String[1];\n        }\n\n\n        boolean enableXposed = VirtualCore.get().isXposedEnabled();\n        if (enableXposed) {\n            VLog.i(TAG, \"Xposed is enabled.\");\n            ClassLoader originClassLoader = context.getClassLoader();\n            ExposedBridge.initOnce(context, data.appInfo, originClassLoader);\n            List<InstalledAppInfo> modules = VirtualCore.get().getInstalledApps(0);\n            for (InstalledAppInfo module : modules) {\n                ExposedBridge.loadModule(module.apkPath, module.getOdexFile().getParent(), module.libPath,\n                        data.appInfo, originClassLoader);\n            }\n        } else {\n            VLog.w(TAG, \"Xposed is disable..\");\n        }\n\n        ClassLoader cl = LoadedApk.getClassLoader.call(data.info);\n        if (BuildCompat.isS()) {\n            ClassLoader parent = cl.getParent();\n            Reflect.on(cl).set(\"parent\", new DelegateLastClassLoader(\"/system/framework/android.test.base.jar\", parent));\n        }\n\n        if (Build.VERSION.SDK_INT >= 30)\n            ApplicationConfig.setDefaultInstance.call(new Object[] { null });\n        mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null);\n\n        // ExposedBridge.patchAppClassLoader(context);\n\n        mirror.android.app.ActivityThread.mInitialApplication.set(mainThread, mInitialApplication);\n        ContextFixer.fixContext(mInitialApplication);\n\n        if (Build.VERSION.SDK_INT >= 24 && \"com.tencent.mm:recovery\".equals(processName)) {\n            fixWeChatRecovery(mInitialApplication);\n        }\n        if (data.providers != null) {\n            installContentProviders(mInitialApplication, data.providers);\n        }\n        if (lock != null) {\n            lock.open();\n            mTempLock = null;\n        }\n        VirtualCore.get().getComponentDelegate().beforeApplicationCreate(mInitialApplication);\n        try {\n            mInstrumentation.callApplicationOnCreate(mInitialApplication);\n            InvocationStubManager.getInstance().checkEnv(HCallbackStub.class);\n            if (conflict) {\n                InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);\n            }\n            Application createdApp = ActivityThread.mInitialApplication.get(mainThread);\n            if (createdApp != null) {\n                mInitialApplication = createdApp;\n            }\n        } catch (Exception e) {\n            if (!mInstrumentation.onException(mInitialApplication, e)) {\n                // 1. tell ui that do not need wait use now.\n                if (mUiCallback != null) {\n                    try {\n                        mUiCallback.onOpenFailed(packageName, VUserHandle.myUserId());\n                    } catch (RemoteException ignored) {\n                    }\n                }\n                // 2. tell vams that launch finish.\n                VActivityManager.get().appDoneExecuting();\n\n                // 3. rethrow\n                throw new RuntimeException(\n                        \"Unable to create application \" + (mInitialApplication == null ? \" [null application] \" : mInitialApplication.getClass().getName())\n                                + \": \" + e.toString(), e);\n            }\n        }\n        VActivityManager.get().appDoneExecuting();\n        VirtualCore.get().getComponentDelegate().afterApplicationCreate(mInitialApplication);\n    }\n\n    private void fixWeChatRecovery(Application app) {\n        try {\n            Field field = app.getClassLoader().loadClass(\"com.tencent.recovery.Recovery\").getField(\"context\");\n            field.setAccessible(true);\n            if (field.get(null) != null) {\n                return;\n            }\n            field.set(null, app.getBaseContext());\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void setupUncaughtHandler() {\n        ThreadGroup root = Thread.currentThread().getThreadGroup();\n        while (root.getParent() != null) {\n            root = root.getParent();\n        }\n        ThreadGroup newRoot = new RootThreadGroup(root);\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            final List<ThreadGroup> groups = mirror.java.lang.ThreadGroup.groups.get(root);\n            //noinspection SynchronizationOnLocalVariableOrMethodParameter\n            synchronized (groups) {\n                List<ThreadGroup> newGroups = new ArrayList<>(groups);\n                newGroups.remove(newRoot);\n                mirror.java.lang.ThreadGroup.groups.set(newRoot, newGroups);\n                groups.clear();\n                groups.add(newRoot);\n                mirror.java.lang.ThreadGroup.groups.set(root, groups);\n                for (ThreadGroup group : newGroups) {\n                    if (group == newRoot) {\n                        continue;\n                    }\n                    mirror.java.lang.ThreadGroup.parent.set(group, newRoot);\n                }\n            }\n        } else {\n            final ThreadGroup[] groups = ThreadGroupN.groups.get(root);\n            //noinspection SynchronizationOnLocalVariableOrMethodParameter\n            synchronized (groups) {\n                ThreadGroup[] newGroups = groups.clone();\n                ThreadGroupN.groups.set(newRoot, newGroups);\n                ThreadGroupN.groups.set(root, new ThreadGroup[]{newRoot});\n                for (Object group : newGroups) {\n                    if (group == newRoot) {\n                        continue;\n                    }\n                    ThreadGroupN.parent.set(group, newRoot);\n                }\n                ThreadGroupN.ngroups.set(root, 1);\n            }\n        }\n    }\n\n    @SuppressLint(\"SdCardPath\")\n    private void startIOUniformer() {\n        ApplicationInfo info = mBoundApplication.appInfo;\n        int userId = VUserHandle.myUserId();\n        String wifiMacAddressFile = deviceInfo.getWifiFile(userId).getPath();\n        NativeEngine.redirectDirectory(\"/sys/class/net/wlan0/address\", wifiMacAddressFile);\n        NativeEngine.redirectDirectory(\"/sys/class/net/eth0/address\", wifiMacAddressFile);\n        NativeEngine.redirectDirectory(\"/sys/class/net/wifi/address\", wifiMacAddressFile);\n\n        NativeEngine.redirectDirectory(\"/data/data/\" + info.packageName, info.dataDir);\n        NativeEngine.redirectDirectory(\"/data/user/0/\" + info.packageName, info.dataDir);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            NativeEngine.redirectDirectory(\"/data/user_de/0/\" + info.packageName, info.dataDir);\n        }\n        String libPath = VEnvironment.getAppLibDirectory(info.packageName).getAbsolutePath();\n        String userLibPath = new File(VEnvironment.getUserSystemDirectory(userId), info.packageName + \"/lib\").getAbsolutePath();\n        NativeEngine.redirectDirectory(userLibPath, libPath);\n        NativeEngine.redirectDirectory(\"/data/data/\" + info.packageName + \"/lib/\", libPath);\n        NativeEngine.redirectDirectory(\"/data/user/0/\" + info.packageName + \"/lib/\", libPath);\n\n        File dataUserLib = new File(VEnvironment.getDataUserPackageDirectory(userId, info.packageName), \"lib\");\n        if (!dataUserLib.exists()) {\n            try {\n                Os.symlink(libPath, dataUserLib.getPath());\n            } catch (ErrnoException e) {\n                VLog.w(TAG, \"symlink error\", e);\n            }\n        }\n\n        setupVirtualStorage(info, userId);\n\n        NativeEngine.enableIORedirect();\n    }\n\n    private void setupVirtualStorage(ApplicationInfo info, int userId) {\n        VirtualStorageManager vsManager = VirtualStorageManager.get();\n        boolean enable = vsManager.isVirtualStorageEnable(info.packageName, userId);\n        // Android 11, force enable storage redirect.\n        if (!enable && !(Build.VERSION.SDK_INT >= 30)) {\n            // There are lots of situation to deal, I am tired, disable it now.\n            // such as: FileProvider.\n            return;\n        }\n\n        File vsDir = VEnvironment.getVirtualStorageDir(info.packageName, userId);\n        if (vsDir == null || !vsDir.exists() || !vsDir.isDirectory()) {\n            return;\n        }\n\n        HashSet<String> storageRoots = getMountPoints();\n        storageRoots.add(Environment.getExternalStorageDirectory().getAbsolutePath());\n\n        Set<String> whiteList = new HashSet<>();\n        whiteList.add(Environment.DIRECTORY_PODCASTS);\n        whiteList.add(Environment.DIRECTORY_RINGTONES);\n        whiteList.add(Environment.DIRECTORY_ALARMS);\n        whiteList.add(Environment.DIRECTORY_NOTIFICATIONS);\n        whiteList.add(Environment.DIRECTORY_PICTURES);\n        whiteList.add(Environment.DIRECTORY_MOVIES);\n        whiteList.add(Environment.DIRECTORY_DOWNLOADS);\n        whiteList.add(Environment.DIRECTORY_DCIM);\n        // Android 11, do not tryna fetch this directory directly or crash.\n        // See docs below...\n        if (Build.VERSION.SDK_INT < 30) {\n            whiteList.add(\"Android/obb\");\n        }\n        if (Build.VERSION.SDK_INT >= 19) {\n            whiteList.add(Environment.DIRECTORY_DOCUMENTS);\n        }\n\n        // ensure virtual storage white directory exists.\n        for (String whiteDir : whiteList) {\n            File originalDir = new File(Environment.getExternalStorageDirectory(), whiteDir);\n            File virtualDir = new File(vsDir, whiteDir);\n            if (!originalDir.exists()) {\n                continue;\n            }\n            //noinspection ResultOfMethodCallIgnored\n            virtualDir.mkdirs();\n        }\n\n        String vsPath = vsDir.getAbsolutePath();\n        NativeEngine.whitelist(vsPath, true);\n        String privatePath = VEnvironment.getVirtualPrivateStorageDir(userId).getAbsolutePath();\n        NativeEngine.whitelist(privatePath, true);\n\n        for (String storageRoot : storageRoots) {\n            for (String whiteDir : whiteList) {\n                // white list, do not redirect\n                String whitePath = new File(storageRoot, whiteDir).getAbsolutePath();\n                NativeEngine.whitelist(whitePath, true);\n            }\n\n            // Android 11 -> see https://developer.android.com/training/data-storage#scoped-storage\n            // 安卓11 打开这个链接看看 https://developer.android.google.cn/training/data-storage#scoped-storage\n            // see https://android-opengrok.bangnimang.net/android-11.0.0_r8/xref/frameworks/base/core/java/android/os/Environment.java\n            // redirect xxx/Android/data/ -> /xxx/Android/data/<host>/virtual/<user>\n            NativeEngine.redirectDirectory(new File(storageRoot, \"Android/data/\").getAbsolutePath(), privatePath);\n            // redirect xxx/Android/obb/ -> /xxx/Android/data/<host>/virtual/<user>\n            NativeEngine.redirectDirectory(new File(storageRoot, \"Android/obb/\").getAbsolutePath(), privatePath);\n            // redirect /sdcard/ -> vsdcard\n            NativeEngine.redirectDirectory(storageRoot, vsPath);\n        }\n    }\n\n    @SuppressLint(\"SdCardPath\")\n    private HashSet<String> getMountPoints() {\n        HashSet<String> mountPoints = new HashSet<>(3);\n        mountPoints.add(\"/mnt/sdcard/\");\n        mountPoints.add(\"/sdcard/\");\n        // Redmi 10X Pro, Pixel 5... More mount points?\n        // 1@die.lu\n        mountPoints.add(\"/storage/self/primary/\");\n        String[] points = StorageManagerCompat.getAllPoints(VirtualCore.get().getContext());\n        if (points != null) {\n            Collections.addAll(mountPoints, points);\n        }\n        return mountPoints;\n\n    }\n\n    private Context createPackageContext(String packageName) {\n        try {\n            Context hostContext = VirtualCore.get().getContext();\n            return hostContext.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n            VirtualRuntime.crash(new RemoteException());\n        }\n        throw new RuntimeException();\n    }\n\n    private Object fixBoundApp(AppBindData data) {\n        Object thread = VirtualCore.mainThread();\n        Object boundApp = mirror.android.app.ActivityThread.mBoundApplication.get(thread);\n        mirror.android.app.ActivityThread.AppBindData.appInfo.set(boundApp, data.appInfo);\n        mirror.android.app.ActivityThread.AppBindData.processName.set(boundApp, data.processName);\n        mirror.android.app.ActivityThread.AppBindData.instrumentationName.set(\n                boundApp,\n                new ComponentName(data.appInfo.packageName, Instrumentation.class.getName())\n        );\n        ActivityThread.AppBindData.providers.set(boundApp, data.providers);\n        return boundApp;\n    }\n\n    private void installContentProviders(Context app, List<ProviderInfo> providers) {\n        long origId = Binder.clearCallingIdentity();\n        Object mainThread = VirtualCore.mainThread();\n        try {\n            for (ProviderInfo cpi : providers) {\n                try {\n                    ActivityThread.installProvider(mainThread, app, cpi, null);\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            }\n        } finally {\n            Binder.restoreCallingIdentity(origId);\n        }\n    }\n\n    @Override\n    public IBinder acquireProviderClient(ProviderInfo info) {\n        if (mTempLock != null) {\n            mTempLock.block();\n        }\n        if (!isBound()) {\n            VClientImpl.get().bindApplication(info.packageName, info.processName);\n        }\n        IInterface provider = null;\n        String[] authorities = info.authority.split(\";\");\n        String authority = authorities.length == 0 ? info.authority : authorities[0];\n        ContentResolver resolver = VirtualCore.get().getContext().getContentResolver();\n        ContentProviderClient client = null;\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                client = resolver.acquireUnstableContentProviderClient(authority);\n            } else {\n                client = resolver.acquireContentProviderClient(authority);\n            }\n        } catch (Throwable e) {\n            VLog.e(TAG, \"\", e);\n        }\n        if (client != null) {\n            provider = mirror.android.content.ContentProviderClient.mContentProvider.get(client);\n            client.release();\n        }\n        return provider != null ? provider.asBinder() : null;\n    }\n\n    private void fixInstalledProviders() {\n        clearSettingProvider();\n        Map clientMap = ActivityThread.mProviderMap.get(VirtualCore.mainThread());\n        for (Object clientRecord : clientMap.values()) {\n            if (BuildCompat.isOreo()) {\n                IInterface provider = ActivityThread.ProviderClientRecordJB.mProvider.get(clientRecord);\n                Object holder = ActivityThread.ProviderClientRecordJB.mHolder.get(clientRecord);\n                if (holder == null) {\n                    continue;\n                }\n                ProviderInfo info = ContentProviderHolderOreo.info.get(holder);\n                if (!info.authority.startsWith(VASettings.STUB_CP_AUTHORITY)) {\n                    provider = ProviderHook.createProxy(true, info.authority, provider);\n                    ActivityThread.ProviderClientRecordJB.mProvider.set(clientRecord, provider);\n                    ContentProviderHolderOreo.provider.set(holder, provider);\n                }\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                IInterface provider = ActivityThread.ProviderClientRecordJB.mProvider.get(clientRecord);\n                Object holder = ActivityThread.ProviderClientRecordJB.mHolder.get(clientRecord);\n                if (holder == null) {\n                    continue;\n                }\n                ProviderInfo info = IActivityManager.ContentProviderHolder.info.get(holder);\n                if (!info.authority.startsWith(VASettings.STUB_CP_AUTHORITY)) {\n                    provider = ProviderHook.createProxy(true, info.authority, provider);\n                    ActivityThread.ProviderClientRecordJB.mProvider.set(clientRecord, provider);\n                    IActivityManager.ContentProviderHolder.provider.set(holder, provider);\n                }\n            } else {\n                String authority = ActivityThread.ProviderClientRecord.mName.get(clientRecord);\n                IInterface provider = ActivityThread.ProviderClientRecord.mProvider.get(clientRecord);\n                if (provider != null && !authority.startsWith(VASettings.STUB_CP_AUTHORITY)) {\n                    provider = ProviderHook.createProxy(true, authority, provider);\n                    ActivityThread.ProviderClientRecord.mProvider.set(clientRecord, provider);\n                }\n            }\n        }\n\n    }\n\n    private void clearSettingProvider() {\n        Object cache;\n        cache = Settings.System.sNameValueCache.get();\n        if (cache != null) {\n            clearContentProvider(cache);\n        }\n        cache = Settings.Secure.sNameValueCache.get();\n        if (cache != null) {\n            clearContentProvider(cache);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && Settings.Global.TYPE != null) {\n            cache = Settings.Global.sNameValueCache.get();\n            if (cache != null) {\n                clearContentProvider(cache);\n            }\n        }\n    }\n\n    private static void clearContentProvider(Object cache) {\n        if (BuildCompat.isOreo()) {\n            Object holder = Settings.NameValueCacheOreo.mProviderHolder.get(cache);\n            if (holder != null) {\n                Settings.ContentProviderHolder.mContentProvider.set(holder, null);\n            }\n        } else {\n            Settings.NameValueCache.mContentProvider.set(cache, null);\n        }\n    }\n\n    @Override\n    public void finishActivity(IBinder token) {\n        VActivityManager.get().finishActivity(token);\n    }\n\n    @Override\n    public void scheduleNewIntent(String creator, IBinder token, Intent intent) {\n        NewIntentData data = new NewIntentData();\n        data.creator = creator;\n        data.token = token;\n        data.intent = intent;\n        sendMessage(NEW_INTENT, data);\n    }\n\n    @Override\n    public void scheduleReceiver(String processName, ComponentName component, Intent intent, PendingResultData resultData) {\n        ReceiverData receiverData = new ReceiverData();\n        receiverData.resultData = resultData;\n        receiverData.intent = intent;\n        receiverData.component = component;\n        receiverData.processName = processName;\n        sendMessage(RECEIVER, receiverData);\n    }\n\n    private void handleReceiver(ReceiverData data) {\n        BroadcastReceiver.PendingResult result = data.resultData.build();\n        try {\n            if (!isBound()) {\n                bindApplication(data.component.getPackageName(), data.processName);\n            }\n            Context context = mInitialApplication.getBaseContext();\n            Context receiverContext = ContextImpl.getReceiverRestrictedContext.call(context);\n            String className = data.component.getClassName();\n            BroadcastReceiver receiver = (BroadcastReceiver) context.getClassLoader().loadClass(className).newInstance();\n            mirror.android.content.BroadcastReceiver.setPendingResult.call(receiver, result);\n            data.intent.setExtrasClassLoader(context.getClassLoader());\n            if (data.intent.getComponent() == null) {\n                data.intent.setComponent(data.component);\n            }\n            receiver.onReceive(receiverContext, data.intent);\n            if (mirror.android.content.BroadcastReceiver.getPendingResult.call(receiver) != null) {\n                result.finish();\n            }\n        } catch (Exception e) {\n            // must be this for misjudge of anti-virus!!\n            throw new RuntimeException(String.format(\"Unable to start receiver: %s \", data.component), e);\n        }\n        VActivityManager.get().broadcastFinish(data.resultData);\n    }\n\n    @Override\n    public IBinder createProxyService(ComponentName component, IBinder binder) {\n        return ProxyServiceFactory.getProxyService(getCurrentApplication(), component, binder);\n    }\n\n    @Override\n    public String getDebugInfo() {\n        return \"process : \" + VirtualRuntime.getProcessName() + \"\\n\" +\n                \"initialPkg : \" + VirtualRuntime.getInitialPackageName() + \"\\n\" +\n                \"vuid : \" + vuid;\n    }\n\n    private static class RootThreadGroup extends ThreadGroup {\n\n        RootThreadGroup(ThreadGroup parent) {\n            super(parent, \"VA-Root\");\n        }\n\n        @Override\n        public void uncaughtException(Thread t, Throwable e) {\n            CrashHandler handler = VClientImpl.gClient.crashHandler;\n            if (handler != null) {\n                handler.handleUncaughtException(t, e);\n            } else {\n                VLog.e(\"uncaught\", e);\n                System.exit(0);\n            }\n        }\n    }\n\n    private final class NewIntentData {\n        String creator;\n        IBinder token;\n        Intent intent;\n    }\n\n    private final class AppBindData {\n        String processName;\n        ApplicationInfo appInfo;\n        List<ProviderInfo> providers;\n        Object info;\n    }\n\n    private final class ReceiverData {\n        PendingResultData resultData;\n        Intent intent;\n        ComponentName component;\n        String processName;\n    }\n\n    private class H extends Handler {\n\n        private H() {\n            super(Looper.getMainLooper());\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            switch (msg.what) {\n                case NEW_INTENT: {\n                    handleNewIntent((NewIntentData) msg.obj);\n                }\n                break;\n                case RECEIVER: {\n                    handleReceiver((ReceiverData) msg.obj);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/badger/BadgerManager.java",
    "content": "package com.lody.virtual.client.badger;\n\nimport android.content.Intent;\n\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.remote.BadgerInfo;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\npublic class BadgerManager {\n\n    private static final Map<String, IBadger> BADGERS = new HashMap<>(10);\n\n    static {\n        addBadger(new BroadcastBadger1.AdwHomeBadger());\n        addBadger(new BroadcastBadger1.AospHomeBadger());\n        addBadger(new BroadcastBadger1.LGHomeBadger());\n        addBadger(new BroadcastBadger1.NewHtcHomeBadger2());\n        addBadger(new BroadcastBadger1.OPPOHomeBader());\n        addBadger(new BroadcastBadger2.NewHtcHomeBadger1());\n\n    }\n\n    private static void addBadger(IBadger badger) {\n        BADGERS.put(badger.getAction(), badger);\n    }\n\n    public static boolean handleBadger(Intent intent) {\n        IBadger badger = BADGERS.get(intent.getAction());\n        if (badger != null) {\n            BadgerInfo info = badger.handleBadger(intent);\n            VActivityManager.get().notifyBadgerChange(info);\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/badger/BroadcastBadger1.java",
    "content": "package com.lody.virtual.client.badger;\n\nimport android.content.Intent;\n\nimport com.lody.virtual.remote.BadgerInfo;\n\n/**\n * @author Lody\n */\npublic abstract class BroadcastBadger1 implements IBadger {\n\n    public abstract String getAction();\n\n    public abstract String getPackageKey();\n\n    public abstract String getClassNameKey();\n\n    public abstract String getCountKey();\n\n    @Override\n    public BadgerInfo handleBadger(Intent intent) {\n        BadgerInfo info = new BadgerInfo();\n        info.packageName = intent.getStringExtra(getPackageKey());\n        if (getClassNameKey() != null) {\n            info.className = intent.getStringExtra(getClassNameKey());\n        }\n        info.badgerCount = intent.getIntExtra(getCountKey(), 0);\n        return info;\n    }\n\n\n    static class LGHomeBadger extends BroadcastBadger1 {\n\n        @Override\n        public String getAction() {\n            return \"android.intent.action.BADGE_COUNT_UPDATE\";\n        }\n\n        @Override\n        public String getPackageKey() {\n            return \"badge_count_package_name\";\n        }\n\n        @Override\n        public String getClassNameKey() {\n            return \"badge_count_class_name\";\n        }\n\n        @Override\n        public String getCountKey() {\n            return \"badge_count\";\n        }\n    }\n\n    static class AdwHomeBadger extends BroadcastBadger1 {\n\n        @Override\n        public String getAction() {\n            return \"org.adw.launcher.counter.SEND\";\n        }\n\n        @Override\n        public String getPackageKey() {\n            return \"PNAME\";\n        }\n\n        @Override\n        public String getClassNameKey() {\n            return \"CNAME\";\n        }\n\n        @Override\n        public String getCountKey() {\n            return \"COUNT\";\n        }\n    }\n\n    static class AospHomeBadger extends BroadcastBadger1 {\n\n        @Override\n        public String getAction() {\n            return \"android.intent.action.BADGE_COUNT_UPDATE\";\n        }\n\n        @Override\n        public String getPackageKey() {\n            return \"badge_count_package_name\";\n        }\n\n        @Override\n        public String getClassNameKey() {\n            return \"badge_count_class_name\";\n        }\n\n        @Override\n        public String getCountKey() {\n            return \"badge_count\";\n        }\n    }\n\n\n    static class NewHtcHomeBadger2 extends BroadcastBadger1 {\n\n        @Override\n        public String getAction() {\n            return \"com.htc.launcher.action.UPDATE_SHORTCUT\";\n        }\n\n        @Override\n        public String getPackageKey() {\n            return \"packagename\";\n        }\n\n        @Override\n        public String getClassNameKey() {\n            return null;\n        }\n\n        @Override\n        public String getCountKey() {\n            return \"count\";\n        }\n    }\n\n\n    static class OPPOHomeBader extends BroadcastBadger1 {\n\n        @Override\n        public String getAction() {\n            return \"com.oppo.unsettledevent\";\n        }\n\n        @Override\n        public String getPackageKey() {\n            return \"pakeageName\";\n        }\n\n        @Override\n        public String getClassNameKey() {\n            return null;\n        }\n\n        @Override\n        public String getCountKey() {\n            return \"number\";\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/badger/BroadcastBadger2.java",
    "content": "package com.lody.virtual.client.badger;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\n\nimport com.lody.virtual.remote.BadgerInfo;\n\n/**\n * @author Lody\n */\npublic abstract class BroadcastBadger2 implements IBadger {\n\n    public abstract String getAction();\n\n    public abstract String getComponentKey();\n\n    public abstract String getCountKey();\n\n    @Override\n    public BadgerInfo handleBadger(Intent intent) {\n        BadgerInfo info = new BadgerInfo();\n        String componentName = intent.getStringExtra(getComponentKey());\n        ComponentName component = ComponentName.unflattenFromString(componentName);\n        if (component != null) {\n            info.packageName = component.getPackageName();\n            info.className = component.getClassName();\n            info.badgerCount = intent.getIntExtra(getCountKey(), 0);\n            return info;\n        }\n        return null;\n    }\n\n\n    static class NewHtcHomeBadger1 extends BroadcastBadger2 {\n\n        @Override\n        public String getAction() {\n            return \"com.htc.launcher.action.SET_NOTIFICATION\";\n        }\n\n        @Override\n        public String getComponentKey() {\n            return \"com.htc.launcher.extra.COMPONENT\";\n        }\n\n\n        @Override\n        public String getCountKey() {\n            return \"com.htc.launcher.extra.COUNT\";\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/badger/IBadger.java",
    "content": "package com.lody.virtual.client.badger;\n\nimport android.content.Intent;\n\nimport com.lody.virtual.remote.BadgerInfo;\n\n/**\n * @author Lody\n */\npublic interface IBadger {\n\n    String getAction();\n\n    BadgerInfo handleBadger(Intent intent);\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/core/CrashHandler.java",
    "content": "package com.lody.virtual.client.core;\n\n/**\n * @author Lody\n */\n\npublic interface CrashHandler {\n\n    void handleUncaughtException(Thread t, Throwable e);\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InstallStrategy.java",
    "content": "package com.lody.virtual.client.core;\n\n/**\n * @author Lody\n *\n *\n */\npublic interface InstallStrategy {\n\tint TERMINATE_IF_EXIST = 0x01 << 1;\n\tint UPDATE_IF_EXIST = 0x01 << 2;\n\tint COMPARE_VERSION = 0X01 << 3;\n\tint IGNORE_NEW_VERSION = 0x01 << 4;\n\tint DEPEND_SYSTEM_IF_EXIST = 0x01 << 5;\n\tint SKIP_DEX_OPT = 0x01 << 6;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java",
    "content": "package com.lody.virtual.client.core;\n\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.delegate.AppInstrumentation;\nimport com.lody.virtual.client.hook.proxies.account.AccountManagerStub;\nimport com.lody.virtual.client.hook.proxies.alarm.AlarmManagerStub;\nimport com.lody.virtual.client.hook.proxies.am.ActivityManagerStub;\nimport com.lody.virtual.client.hook.proxies.am.ActivityTaskManagerStub;\nimport com.lody.virtual.client.hook.proxies.am.HCallbackStub;\nimport com.lody.virtual.client.hook.proxies.am.TransactionHandlerStub;\nimport com.lody.virtual.client.hook.proxies.appops.AppOpsManagerStub;\nimport com.lody.virtual.client.hook.proxies.appwidget.AppWidgetManagerStub;\nimport com.lody.virtual.client.hook.proxies.audio.AudioManagerStub;\nimport com.lody.virtual.client.hook.proxies.backup.BackupManagerStub;\nimport com.lody.virtual.client.hook.proxies.battery.BatteryStatsStub;\nimport com.lody.virtual.client.hook.proxies.bluetooth.BluetoothStub;\nimport com.lody.virtual.client.hook.proxies.clipboard.ClipBoardStub;\nimport com.lody.virtual.client.hook.proxies.connectivity.ConnectivityStub;\nimport com.lody.virtual.client.hook.proxies.content.ContentServiceStub;\nimport com.lody.virtual.client.hook.proxies.context_hub.ContextHubServiceStub;\nimport com.lody.virtual.client.hook.proxies.devicepolicy.DevicePolicyManagerStub;\nimport com.lody.virtual.client.hook.proxies.display.DisplayStub;\nimport com.lody.virtual.client.hook.proxies.dropbox.DropBoxManagerStub;\nimport com.lody.virtual.client.hook.proxies.fingerprint.FingerprintManagerStub;\nimport com.lody.virtual.client.hook.proxies.graphics.GraphicsStatsStub;\nimport com.lody.virtual.client.hook.proxies.imms.MmsStub;\nimport com.lody.virtual.client.hook.proxies.input.InputMethodManagerStub;\nimport com.lody.virtual.client.hook.proxies.isms.ISmsStub;\nimport com.lody.virtual.client.hook.proxies.isub.ISubStub;\nimport com.lody.virtual.client.hook.proxies.job.JobServiceStub;\nimport com.lody.virtual.client.hook.proxies.libcore.LibCoreStub;\nimport com.lody.virtual.client.hook.proxies.location.LocationManagerStub;\nimport com.lody.virtual.client.hook.proxies.media.router.MediaRouterServiceStub;\nimport com.lody.virtual.client.hook.proxies.media.session.SessionManagerStub;\nimport com.lody.virtual.client.hook.proxies.mount.MountServiceStub;\nimport com.lody.virtual.client.hook.proxies.network.NetworkManagementStub;\nimport com.lody.virtual.client.hook.proxies.notification.NotificationManagerStub;\nimport com.lody.virtual.client.hook.proxies.os.DeviceIdentifiersPolicyServiceStub;\nimport com.lody.virtual.client.hook.proxies.persistent_data_block.PersistentDataBlockServiceStub;\nimport com.lody.virtual.client.hook.proxies.phonesubinfo.PhoneSubInfoStub;\nimport com.lody.virtual.client.hook.proxies.pm.LauncherAppsStub;\nimport com.lody.virtual.client.hook.proxies.pm.PackageManagerStub;\nimport com.lody.virtual.client.hook.proxies.power.PowerManagerStub;\nimport com.lody.virtual.client.hook.proxies.restriction.RestrictionStub;\nimport com.lody.virtual.client.hook.proxies.search.SearchManagerStub;\nimport com.lody.virtual.client.hook.proxies.shortcut.ShortcutServiceStub;\nimport com.lody.virtual.client.hook.proxies.telephony.TelephonyRegistryStub;\nimport com.lody.virtual.client.hook.proxies.telephony.TelephonyStub;\nimport com.lody.virtual.client.hook.proxies.usage.UsageStatsManagerStub;\nimport com.lody.virtual.client.hook.proxies.user.UserManagerStub;\nimport com.lody.virtual.client.hook.proxies.vibrator.VibratorStub;\nimport com.lody.virtual.client.hook.proxies.view.AutoFillManagerStub;\nimport com.lody.virtual.client.hook.proxies.wifi.WifiManagerStub;\nimport com.lody.virtual.client.hook.proxies.wifi_scanner.WifiScannerStub;\nimport com.lody.virtual.client.hook.proxies.window.WindowManagerStub;\nimport com.lody.virtual.client.interfaces.IInjector;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;\nimport static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;\nimport static android.os.Build.VERSION_CODES.KITKAT;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;\nimport static android.os.Build.VERSION_CODES.M;\nimport static android.os.Build.VERSION_CODES.N;\n\n/**\n * @author Lody\n *\n */\npublic final class InvocationStubManager {\n\n    private static InvocationStubManager sInstance = new InvocationStubManager();\n    private static boolean sInit;\n\n\tprivate Map<Class<?>, IInjector> mInjectors = new HashMap<>(13);\n\n\tprivate InvocationStubManager() {\n\t}\n\n\tpublic static InvocationStubManager getInstance() {\n\t\treturn sInstance;\n\t}\n\n\tvoid injectAll() throws Throwable {\n\t\tfor (IInjector injector : mInjectors.values()) {\n\t\t\tinjector.inject();\n\t\t}\n\t\t// XXX: Lazy inject the Instrumentation,\n\t\taddInjector(AppInstrumentation.getDefault());\n\t}\n\n    /**\n\t * @return if the InvocationStubManager has been initialized.\n\t */\n\tpublic boolean isInit() {\n\t\treturn sInit;\n\t}\n\n\n\tpublic void init() throws Throwable {\n\t\tif (isInit()) {\n\t\t\tthrow new IllegalStateException(\"InvocationStubManager Has been initialized.\");\n\t\t}\n\t\tinjectInternal();\n\t\tsInit = true;\n\n\t}\n\n\tprivate void injectInternal() throws Throwable {\n\t\tif (VirtualCore.get().isMainProcess()) {\n\t\t\treturn;\n\t\t}\n\t\tif (VirtualCore.get().isServerProcess()) {\n\t\t\taddInjector(new ActivityManagerStub());\n\t\t\taddInjector(new PackageManagerStub());\n\t\t\treturn;\n\t\t}\n\t\tif (VirtualCore.get().isVAppProcess()) {\n\t\t\taddInjector(new LibCoreStub());\n\t\t\taddInjector(new ActivityManagerStub());\n\t\t\taddInjector(new PackageManagerStub());\n\t\t\tif (Build.VERSION.SDK_INT >= 28) {\n\t\t\t\taddInjector(new TransactionHandlerStub());\n\t\t\t}\n\t\t\taddInjector(HCallbackStub.getDefault());\n\t\t\taddInjector(new ISmsStub());\n\t\t\taddInjector(new ISubStub());\n\t\t\taddInjector(new DropBoxManagerStub());\n\t\t\taddInjector(new NotificationManagerStub());\n\t\t\taddInjector(new LocationManagerStub());\n\t\t\taddInjector(new WindowManagerStub());\n\t\t\taddInjector(new ClipBoardStub());\n\t\t\taddInjector(new MountServiceStub());\n\t\t\taddInjector(new BackupManagerStub());\n\t\t\taddInjector(new TelephonyStub());\n\t\t\taddInjector(new TelephonyRegistryStub());\n\t\t\taddInjector(new PhoneSubInfoStub());\n\t\t\taddInjector(new PowerManagerStub());\n\t\t\taddInjector(new AppWidgetManagerStub());\n\t\t\taddInjector(new AccountManagerStub());\n\t\t\taddInjector(new AudioManagerStub());\n\t\t\taddInjector(new SearchManagerStub());\n\t\t\taddInjector(new ContentServiceStub());\n\t\t\taddInjector(new ConnectivityStub());\n\n\t\t\tif (Build.VERSION.SDK_INT >= JELLY_BEAN_MR2) {\n\t\t\t\taddInjector(new VibratorStub());\n\t\t\t\taddInjector(new WifiManagerStub());\n\t\t\t\taddInjector(new BluetoothStub());\n\t\t\t\taddInjector(new ContextHubServiceStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= JELLY_BEAN_MR1) {\n\t\t\t\taddInjector(new UserManagerStub());\n\t\t\t}\n\n\t\t\tif (Build.VERSION.SDK_INT >= JELLY_BEAN_MR1) {\n\t\t\t\taddInjector(new DisplayStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= LOLLIPOP) {\n\t\t\t\taddInjector(new PersistentDataBlockServiceStub());\n\t\t\t\taddInjector(new InputMethodManagerStub());\n\t\t\t\taddInjector(new MmsStub());\n\t\t\t\taddInjector(new SessionManagerStub());\n\t\t\t\taddInjector(new JobServiceStub());\n\t\t\t\taddInjector(new RestrictionStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= KITKAT) {\n\t\t\t\taddInjector(new AlarmManagerStub());\n\t\t\t\taddInjector(new AppOpsManagerStub());\n\t\t\t\taddInjector(new MediaRouterServiceStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= LOLLIPOP_MR1) {\n\t\t\t\taddInjector(new GraphicsStatsStub());\n\t\t\t\taddInjector(new UsageStatsManagerStub());\n\t\t\t\taddInjector(new LauncherAppsStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= M) {\n\t\t\t\taddInjector(new FingerprintManagerStub());\n\t\t\t\taddInjector(new NetworkManagementStub());\n\t\t\t}\n\t\t\tif (Build.VERSION.SDK_INT >= N) {\n                addInjector(new WifiScannerStub());\n                addInjector(new ShortcutServiceStub());\n                addInjector(new DevicePolicyManagerStub());\n\n                addInjector(new BatteryStatsStub());\n            }\n            if (BuildCompat.isOreo()) {\n\t\t\t\taddInjector(new AutoFillManagerStub());\n\t\t\t}\n            if (BuildCompat.isQ()) {\n            \taddInjector(new ActivityTaskManagerStub());\n\n            \t// http://aospxref.com/android-10.0.0_r47/xref/frameworks/base/core/java/android/os/IDeviceIdentifiersPolicyService.aidl#24\n            \taddInjector(new DeviceIdentifiersPolicyServiceStub());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addInjector(IInjector IInjector) {\n\t\tmInjectors.put(IInjector.getClass(), IInjector);\n\t}\n\n\tpublic <T extends IInjector> T findInjector(Class<T> clazz) {\n\t\t// noinspection unchecked\n\t\treturn (T) mInjectors.get(clazz);\n\t}\n\n\tpublic <T extends IInjector> void checkEnv(Class<T> clazz) {\n\t\tIInjector IInjector = findInjector(clazz);\n\t\tif (IInjector != null && IInjector.isEnvBad()) {\n\t\t\ttry {\n\t\t\t\tIInjector.inject();\n\t\t\t} catch (Throwable e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic <T extends IInjector, H extends MethodInvocationStub> H getInvocationStub(Class<T> injectorClass) {\n\t\tT injector = findInjector(injectorClass);\n\t\tif (injector != null && injector instanceof MethodInvocationProxy) {\n\t\t\t// noinspection unchecked\n\t\t\treturn (H) ((MethodInvocationProxy) injector).getInvocationStub();\n\t\t}\n\t\treturn null;\n\t}\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java",
    "content": "package com.lody.virtual.client.core;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.app.ActivityManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.ShortcutInfo;\nimport android.content.pm.ShortcutManager;\nimport android.content.res.AssetManager;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Icon;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.ConditionVariable;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.fixer.ContextFixer;\nimport com.lody.virtual.client.hook.delegate.ComponentDelegate;\nimport com.lody.virtual.client.hook.delegate.PhoneInfoDelegate;\nimport com.lody.virtual.client.hook.delegate.TaskDescriptionDelegate;\nimport com.lody.virtual.client.ipc.LocalProxyUtils;\nimport com.lody.virtual.client.ipc.ServiceManagerNative;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.compat.BundleCompat;\nimport com.lody.virtual.helper.utils.BitmapUtils;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstallResult;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.server.IAppManager;\nimport com.lody.virtual.server.interfaces.IAppRequestListener;\nimport com.lody.virtual.server.interfaces.IPackageObserver;\nimport com.lody.virtual.server.interfaces.IUiCallback;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport me.weishu.reflection.Reflection;\nimport mirror.android.app.ActivityThread;\n\n/**\n * @author Lody\n * @version 3.5\n */\npublic final class VirtualCore {\n\n    public static final int GET_HIDDEN_APP = 0x00000001;\n\n    public static final String TAICHI_PACKAGE = \"me.weishu.exp\";\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static VirtualCore gCore = new VirtualCore();\n    private final int myUid = Process.myUid();\n    /**\n     * Client Package Manager\n     */\n    private PackageManager unHookPackageManager;\n    /**\n     * Host package name\n     */\n    private String hostPkgName;\n    /**\n     * ActivityThread instance\n     */\n    private Object mainThread;\n    private Context context;\n    /**\n     * Main ProcessName\n     */\n    private String mainProcessName;\n    /**\n     * Real Process Name\n     */\n    private String processName;\n    private ProcessType processType;\n    private IAppManager mService;\n    private boolean isStartUp;\n    private PackageInfo hostPkgInfo;\n    private int systemPid;\n    private ConditionVariable initLock = new ConditionVariable();\n    private PhoneInfoDelegate phoneInfoDelegate;\n    private ComponentDelegate componentDelegate;\n    private TaskDescriptionDelegate taskDescriptionDelegate;\n\n    private VirtualCore() {\n    }\n\n    public static VirtualCore get() {\n        return gCore;\n    }\n\n    public static PackageManager getPM() {\n        return get().getPackageManager();\n    }\n\n    public static Object mainThread() {\n        return get().mainThread;\n    }\n\n    public ConditionVariable getInitLock() {\n        return initLock;\n    }\n\n    public int myUid() {\n        return myUid;\n    }\n\n    public int myUserId() {\n        return VUserHandle.getUserId(myUid);\n    }\n\n    public ComponentDelegate getComponentDelegate() {\n        return componentDelegate == null ? ComponentDelegate.EMPTY : componentDelegate;\n    }\n\n    public void setComponentDelegate(ComponentDelegate delegate) {\n        this.componentDelegate = delegate;\n    }\n\n    public PhoneInfoDelegate getPhoneInfoDelegate() {\n        return phoneInfoDelegate;\n    }\n\n    public void setPhoneInfoDelegate(PhoneInfoDelegate phoneInfoDelegate) {\n        this.phoneInfoDelegate = phoneInfoDelegate;\n    }\n\n    public void setCrashHandler(CrashHandler handler) {\n        VClientImpl.get().setCrashHandler(handler);\n    }\n\n    public TaskDescriptionDelegate getTaskDescriptionDelegate() {\n        return taskDescriptionDelegate;\n    }\n\n    public void setTaskDescriptionDelegate(TaskDescriptionDelegate taskDescriptionDelegate) {\n        this.taskDescriptionDelegate = taskDescriptionDelegate;\n    }\n\n    public int[] getGids() {\n        return hostPkgInfo.gids;\n    }\n\n    public Context getContext() {\n        return context;\n    }\n\n    public PackageManager getPackageManager() {\n        return context.getPackageManager();\n    }\n\n    public String getHostPkg() {\n        return hostPkgName;\n    }\n\n    public PackageManager getUnHookPackageManager() {\n        return unHookPackageManager;\n    }\n\n\n    public void startup(Context context) throws Throwable {\n        if (!isStartUp) {\n            if (Looper.myLooper() != Looper.getMainLooper()) {\n                throw new IllegalStateException(\"VirtualCore.startup() must called in main thread.\");\n            }\n            Reflection.unseal(context);\n\n            VASettings.STUB_CP_AUTHORITY = context.getPackageName() + \".\" + VASettings.STUB_DEF_AUTHORITY;\n            ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + \".\" + ServiceManagerNative.SERVICE_DEF_AUTH;\n            this.context = context;\n            mainThread = ActivityThread.currentActivityThread.call();\n            unHookPackageManager = context.getPackageManager();\n            hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);\n            detectProcessType();\n            InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();\n            invocationStubManager.init();\n            invocationStubManager.injectAll();\n            ContextFixer.fixContext(context);\n            isStartUp = true;\n            if (initLock != null) {\n                initLock.open();\n                initLock = null;\n            }\n        }\n    }\n\n    public void waitForEngine() {\n        ServiceManagerNative.ensureServerStarted();\n    }\n\n    public boolean isEngineLaunched() {\n        String engineProcessName = getEngineProcessName();\n        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n        for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {\n            if (info.processName.endsWith(engineProcessName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public String getEngineProcessName() {\n        return context.getString(R.string.engine_process_name);\n    }\n\n    public void initialize(VirtualInitializer initializer) {\n        if (initializer == null) {\n            throw new IllegalStateException(\"Initializer = NULL\");\n        }\n        switch (processType) {\n            case Main:\n                initializer.onMainProcess();\n                break;\n            case VAppClient:\n                initializer.onVirtualProcess();\n                break;\n            case Server:\n                initializer.onServerProcess();\n                break;\n            case CHILD:\n                initializer.onChildProcess();\n                break;\n        }\n    }\n\n    private void detectProcessType() {\n        // Host package name\n        hostPkgName = context.getApplicationInfo().packageName;\n        // Main process name\n        mainProcessName = context.getApplicationInfo().processName;\n        // Current process name\n        processName = ActivityThread.getProcessName.call(mainThread);\n        if (processName.equals(mainProcessName)) {\n            processType = ProcessType.Main;\n        } else if (processName.endsWith(Constants.SERVER_PROCESS_NAME)) {\n            processType = ProcessType.Server;\n        } else if (VActivityManager.get().isAppProcess(processName)) {\n            processType = ProcessType.VAppClient;\n        } else {\n            processType = ProcessType.CHILD;\n        }\n        if (isVAppProcess()) {\n            systemPid = VActivityManager.get().getSystemPid();\n        }\n    }\n\n    private IAppManager getService() {\n        if (mService == null\n                || (!VirtualCore.get().isVAppProcess() && !mService.asBinder().pingBinder())) {\n            synchronized (this) {\n                Object remote = getStubInterface();\n                mService = LocalProxyUtils.genProxy(IAppManager.class, remote);\n            }\n        }\n        return mService;\n    }\n\n    private Object getStubInterface() {\n        return IAppManager.Stub\n                .asInterface(ServiceManagerNative.getService(ServiceManagerNative.APP));\n    }\n\n    /**\n     * @return If the current process is used to VA.\n     */\n    public boolean isVAppProcess() {\n        return ProcessType.VAppClient == processType;\n    }\n\n    /**\n     * @return If the current process is the main.\n     */\n    public boolean isMainProcess() {\n        return ProcessType.Main == processType;\n    }\n\n    /**\n     * @return If the current process is the child.\n     */\n    public boolean isChildProcess() {\n        return ProcessType.CHILD == processType;\n    }\n\n    /**\n     * @return If the current process is the server.\n     */\n    public boolean isServerProcess() {\n        return ProcessType.Server == processType;\n    }\n\n    /**\n     * @return the <em>actual</em> process name\n     */\n    public String getProcessName() {\n        return processName;\n    }\n\n    /**\n     * @return the <em>Main</em> process name\n     */\n    public String getMainProcessName() {\n        return mainProcessName;\n    }\n\n    /**\n     * Optimize the Dalvik-Cache for the specified package.\n     *\n     * @param pkg package name\n     * @throws IOException\n     */\n    @Deprecated\n    public void preOpt(String pkg) throws IOException {\n        /*\n        InstalledAppInfo info = getInstalledAppInfo(pkg, 0);\n        if (info != null && !info.dependSystem) {\n            DexFile.loadDex(info.apkPath, info.getOdexFile().getPath(), 0).close();\n        }*/\n    }\n\n    /**\n     * Is the specified app running in foreground / background?\n     *\n     * @param packageName package name\n     * @param userId      user id\n     * @return if the specified app running in foreground / background.\n     */\n    public boolean isAppRunning(String packageName, int userId) {\n        return VActivityManager.get().isAppRunning(packageName, userId);\n    }\n\n    public InstallResult installPackage(String apkPath, int flags) {\n        try {\n            return getService().installPackage(apkPath, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean clearPackage(String packageName) {\n        try {\n            return getService().clearPackage(packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean clearPackageAsUser(int userId, String packageName) {\n        try {\n            return getService().clearPackageAsUser(userId, packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void addVisibleOutsidePackage(String pkg) {\n        try {\n            getService().addVisibleOutsidePackage(pkg);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void removeVisibleOutsidePackage(String pkg) {\n        try {\n            getService().removeVisibleOutsidePackage(pkg);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isOutsidePackageVisible(String pkg) {\n        try {\n            return getService().isOutsidePackageVisible(pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isXposedEnabled() {\n        return !VirtualCore.get().getContext().getFileStreamPath(\".disable_xposed\").exists();\n    }\n\n    public boolean isAppInstalled(String pkg) {\n        try {\n            return getService().isAppInstalled(pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isPackageLaunchable(String packageName) {\n        InstalledAppInfo info = getInstalledAppInfo(packageName, 0);\n        return info != null\n                && getLaunchIntent(packageName, info.getInstalledUsers()[0]) != null;\n    }\n\n    public Intent getLaunchIntent(String packageName, int userId) {\n        VPackageManager pm = VPackageManager.get();\n        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);\n        intentToResolve.addCategory(Intent.CATEGORY_INFO);\n        intentToResolve.setPackage(packageName);\n        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, intentToResolve.resolveType(context), 0, userId);\n\n        // Otherwise, try to find a main launcher activity.\n        if (ris == null || ris.size() <= 0) {\n            // reuse the intent instance\n            intentToResolve.removeCategory(Intent.CATEGORY_INFO);\n            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);\n            intentToResolve.setPackage(packageName);\n            ris = pm.queryIntentActivities(intentToResolve, intentToResolve.resolveType(context), 0, userId);\n        }\n        if (ris == null || ris.size() <= 0) {\n            return null;\n        }\n\n        ActivityInfo activityInfo = null;\n        for (ResolveInfo resolveInfo : ris) {\n            if (resolveInfo.activityInfo.enabled) {\n                // select the first enabled component\n                activityInfo = resolveInfo.activityInfo;\n                break;\n            }\n        }\n\n        if (activityInfo == null) {\n            activityInfo = ris.get(0).activityInfo;\n        }\n\n        Intent intent = new Intent(intentToResolve);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.setClassName(activityInfo.packageName,\n                activityInfo.name);\n        return intent;\n    }\n\n    public boolean createShortcut(int userId, String packageName, OnEmitShortcutListener listener) {\n        return createShortcut(userId, packageName, null, listener);\n    }\n\n    public boolean createShortcut(int userId, String packageName, Intent splash, OnEmitShortcutListener listener) {\n        InstalledAppInfo setting = getInstalledAppInfo(packageName, 0);\n        if (setting == null) {\n            return false;\n        }\n        ApplicationInfo appInfo = setting.getApplicationInfo(userId);\n        PackageManager pm = context.getPackageManager();\n        String name;\n        Bitmap icon;\n        String id = packageName + userId;\n        try {\n            CharSequence sequence = appInfo.loadLabel(pm);\n            name = sequence.toString();\n            icon = BitmapUtils.drawableToBitmap(appInfo.loadIcon(pm));\n        } catch (Throwable e) {\n            return false;\n        }\n        if (listener != null) {\n            String newName = listener.getName(name);\n            if (newName != null) {\n                name = newName;\n            }\n            Bitmap newIcon = listener.getIcon(icon);\n            if (newIcon != null) {\n                icon = newIcon;\n            }\n        }\n        Intent targetIntent = getLaunchIntent(packageName, userId);\n        if (targetIntent == null) {\n            return false;\n        }\n        Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);\n        shortcutIntent.setClassName(getHostPkg(), Constants.SHORTCUT_PROXY_ACTIVITY_NAME);\n        shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);\n        if (splash != null) {\n            shortcutIntent.putExtra(\"_VA_|_splash_\", splash.toUri(0));\n        }\n        shortcutIntent.putExtra(\"_VA_|_intent_\", targetIntent);\n        shortcutIntent.putExtra(\"_VA_|_uri_\", targetIntent.toUri(0));\n        shortcutIntent.putExtra(\"_VA_|_user_id_\", userId);\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {\n            // bad parcel.\n            shortcutIntent.removeExtra(\"_VA_|_intent_\");\n\n            Icon withBitmap = Icon.createWithBitmap(icon);\n            ShortcutInfo likeShortcut = new ShortcutInfo.Builder(context, id)\n                    .setShortLabel(name)\n                    .setLongLabel(name)\n                    .setIcon(withBitmap)\n                    .setIntent(shortcutIntent)\n                    .build();\n\n            // crate app shortcuts.\n            createShortcutAboveN(context, likeShortcut);\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                return createDeskShortcutAboveO(context, likeShortcut);\n            }\n        }\n\n\n        Intent addIntent = new Intent();\n        addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);\n        addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);\n        addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);\n        addIntent.setAction(\"com.android.launcher.action.INSTALL_SHORTCUT\");\n        try {\n            context.sendBroadcast(addIntent);\n        } catch (Throwable ignored) {\n            return false;\n        }\n        return true;\n    }\n\n    @TargetApi(Build.VERSION_CODES.N_MR1)\n    private static boolean createShortcutAboveN(Context context, ShortcutInfo likeShortcut) {\n        ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);\n        if (shortcutManager == null) {\n            return false;\n        }\n        try {\n            int max = shortcutManager.getMaxShortcutCountPerActivity();\n            List<ShortcutInfo> dynamicShortcuts = shortcutManager.getDynamicShortcuts();\n            if (dynamicShortcuts.size() >= max) {\n                Collections.sort(dynamicShortcuts, new Comparator<ShortcutInfo>() {\n                    @Override\n                    public int compare(ShortcutInfo o1, ShortcutInfo o2) {\n                        long r = o1.getLastChangedTimestamp() - o2.getLastChangedTimestamp();\n                        return r == 0 ? 0 : (r > 0 ? 1 : -1);\n                    }\n                });\n\n                ShortcutInfo remove = dynamicShortcuts.remove(0);// remove old.\n                shortcutManager.removeDynamicShortcuts(Collections.singletonList(remove.getId()));\n            }\n\n            shortcutManager.addDynamicShortcuts(Collections.singletonList(likeShortcut));\n            return true;\n        } catch (Throwable e) {\n            return false;\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.O)\n    private static boolean createDeskShortcutAboveO(Context context, ShortcutInfo info) {\n        ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);\n        if (shortcutManager == null) {\n            return false;\n        }\n        if (shortcutManager.isRequestPinShortcutSupported()) {\n            // 当添加快捷方式的确认弹框弹出来时，将被回调\n            // PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(context, 0,\n            // new Intent(context, MyReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);\n\n            List<ShortcutInfo> pinnedShortcuts = shortcutManager.getPinnedShortcuts();\n            boolean exists = false;\n            for (ShortcutInfo pinnedShortcut : pinnedShortcuts) {\n                if (TextUtils.equals(pinnedShortcut.getId(), info.getId())) {\n                    // already exist.\n                    exists = true;\n                    Toast.makeText(context, R.string.create_shortcut_already_exist, Toast.LENGTH_SHORT).show();\n                    break;\n                }\n            }\n            if (!exists) {\n                shortcutManager.requestPinShortcut(info, null);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    public boolean removeShortcut(int userId, String packageName, Intent splash, OnEmitShortcutListener listener) {\n        InstalledAppInfo setting = getInstalledAppInfo(packageName, 0);\n        if (setting == null) {\n            return false;\n        }\n        ApplicationInfo appInfo = setting.getApplicationInfo(userId);\n        PackageManager pm = context.getPackageManager();\n        String name;\n        try {\n            CharSequence sequence = appInfo.loadLabel(pm);\n            name = sequence.toString();\n        } catch (Throwable e) {\n            return false;\n        }\n        if (listener != null) {\n            String newName = listener.getName(name);\n            if (newName != null) {\n                name = newName;\n            }\n        }\n        Intent targetIntent = getLaunchIntent(packageName, userId);\n        if (targetIntent == null) {\n            return false;\n        }\n        Intent shortcutIntent = new Intent();\n        shortcutIntent.setClassName(getHostPkg(), Constants.SHORTCUT_PROXY_ACTIVITY_NAME);\n        shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);\n        if (splash != null) {\n            shortcutIntent.putExtra(\"_VA_|_splash_\", splash.toUri(0));\n        }\n        shortcutIntent.putExtra(\"_VA_|_intent_\", targetIntent);\n        shortcutIntent.putExtra(\"_VA_|_uri_\", targetIntent.toUri(0));\n        shortcutIntent.putExtra(\"_VA_|_user_id_\", VUserHandle.myUserId());\n\n        Intent addIntent = new Intent();\n        addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);\n        addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);\n        addIntent.setAction(\"com.android.launcher.action.UNINSTALL_SHORTCUT\");\n        context.sendBroadcast(addIntent);\n        return true;\n    }\n\n    public abstract static class UiCallback extends IUiCallback.Stub {\n    }\n\n    public void setUiCallback(Intent intent, IUiCallback callback) {\n        if (callback != null) {\n            Bundle bundle = new Bundle();\n            BundleCompat.putBinder(bundle, \"_VA_|_ui_callback_\", callback.asBinder());\n            intent.putExtra(\"_VA_|_sender_\", bundle);\n        }\n    }\n\n    public static IUiCallback getUiCallback(Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        // only for launch intent.\n        if (!Intent.ACTION_MAIN.equals(intent.getAction())) {\n            return null;\n        }\n        try {\n            Bundle bundle = intent.getBundleExtra(\"_VA_|_sender_\");\n            if (bundle != null) {\n                IBinder uicallbackToken = BundleCompat.getBinder(bundle, \"_VA_|_ui_callback_\");\n                return IUiCallback.Stub.asInterface(uicallbackToken);\n            }\n        } catch (Throwable ignored) {\n        }\n        return null;\n    }\n\n    public InstalledAppInfo getInstalledAppInfo(String pkg, int flags) {\n        try {\n            return getService().getInstalledAppInfo(pkg, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int getInstalledAppCount() {\n        try {\n            return getService().getInstalledAppCount();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isStartup() {\n        return isStartUp;\n    }\n\n    public boolean uninstallPackageAsUser(String pkgName, int userId) {\n        try {\n            return getService().uninstallPackageAsUser(pkgName, userId);\n        } catch (RemoteException e) {\n            // Ignore\n        }\n        return false;\n    }\n\n    public boolean uninstallPackage(String pkgName) {\n        try {\n            return getService().uninstallPackage(pkgName);\n        } catch (RemoteException e) {\n            // Ignore\n        }\n        return false;\n    }\n\n    public Resources getResources(String pkg) throws Resources.NotFoundException {\n        InstalledAppInfo installedAppInfo = getInstalledAppInfo(pkg, 0);\n        if (installedAppInfo != null) {\n            AssetManager assets = mirror.android.content.res.AssetManager.ctor.newInstance();\n            mirror.android.content.res.AssetManager.addAssetPath.call(assets, installedAppInfo.apkPath);\n            if (installedAppInfo.splitCodePaths != null) {\n                for (String splitCodePath : installedAppInfo.splitCodePaths) {\n                    mirror.android.content.res.AssetManager.addAssetPath.call(assets, splitCodePath);\n                }\n            }\n            Resources hostRes = context.getResources();\n            return new Resources(assets, hostRes.getDisplayMetrics(), hostRes.getConfiguration());\n        }\n        throw new Resources.NotFoundException(pkg);\n    }\n\n    public synchronized ActivityInfo resolveActivityInfo(Intent intent, int userId) {\n        ActivityInfo activityInfo = null;\n        if (intent.getComponent() == null) {\n            ResolveInfo resolveInfo = VPackageManager.get().resolveIntent(intent, intent.getType(), 0, userId);\n            if (resolveInfo != null && resolveInfo.activityInfo != null) {\n                activityInfo = resolveInfo.activityInfo;\n                intent.setClassName(activityInfo.packageName, activityInfo.name);\n            }\n        } else {\n            activityInfo = resolveActivityInfo(intent.getComponent(), userId);\n        }\n        if (activityInfo != null) {\n            if (activityInfo.targetActivity != null) {\n                ComponentName componentName = new ComponentName(activityInfo.packageName, activityInfo.targetActivity);\n                activityInfo = VPackageManager.get().getActivityInfo(componentName, 0, userId);\n                intent.setComponent(componentName);\n            }\n        }\n        return activityInfo;\n    }\n\n    public ActivityInfo resolveActivityInfo(ComponentName componentName, int userId) {\n        return VPackageManager.get().getActivityInfo(componentName, 0, userId);\n    }\n\n    public ServiceInfo resolveServiceInfo(Intent intent, int userId) {\n        ServiceInfo serviceInfo = null;\n        ResolveInfo resolveInfo = VPackageManager.get().resolveService(intent, intent.getType(), 0, userId);\n        if (resolveInfo != null) {\n            serviceInfo = resolveInfo.serviceInfo;\n        }\n        return serviceInfo;\n    }\n\n    public void killApp(String pkg, int userId) {\n        VActivityManager.get().killAppByPkg(pkg, userId);\n    }\n\n    public void killAllApps() {\n        VActivityManager.get().killAllApps();\n    }\n\n    public List<InstalledAppInfo> getInstalledApps(int flags) {\n        try {\n            return getService().getInstalledApps(flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<InstalledAppInfo> getInstalledAppsAsUser(int userId, int flags) {\n        try {\n            return getService().getInstalledAppsAsUser(userId, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void clearAppRequestListener() {\n        try {\n            getService().clearAppRequestListener();\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void scanApps() {\n        try {\n            getService().scanApps();\n        } catch (RemoteException e) {\n            // Ignore\n        }\n    }\n\n    public IAppRequestListener getAppRequestListener() {\n        try {\n            return getService().getAppRequestListener();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setAppRequestListener(final AppRequestListener listener) {\n        IAppRequestListener inner = new IAppRequestListener.Stub() {\n            @Override\n            public void onRequestInstall(final String path) {\n                VirtualRuntime.getUIHandler().post(new Runnable() {\n                    @Override\n                    public void run() {\n                        listener.onRequestInstall(path);\n                    }\n                });\n            }\n\n            @Override\n            public void onRequestUninstall(final String pkg) {\n                VirtualRuntime.getUIHandler().post(new Runnable() {\n                    @Override\n                    public void run() {\n                        listener.onRequestUninstall(pkg);\n                    }\n                });\n            }\n        };\n        try {\n            getService().setAppRequestListener(inner);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean isPackageLaunched(int userId, String packageName) {\n        try {\n            return getService().isPackageLaunched(userId, packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setPackageHidden(int userId, String packageName, boolean hidden) {\n        try {\n            getService().setPackageHidden(userId, packageName, hidden);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean installPackageAsUser(int userId, String packageName) {\n        try {\n            return getService().installPackageAsUser(userId, packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isAppInstalledAsUser(int userId, String packageName) {\n        try {\n            return getService().isAppInstalledAsUser(userId, packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int[] getPackageInstalledUsers(String packageName) {\n        try {\n            return getService().getPackageInstalledUsers(packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public abstract static class PackageObserver extends IPackageObserver.Stub {\n    }\n\n    public void registerObserver(IPackageObserver observer) {\n        try {\n            getService().registerObserver(observer);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void unregisterObserver(IPackageObserver observer) {\n        try {\n            getService().unregisterObserver(observer);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isOutsideInstalled(String packageName) {\n        try {\n            return unHookPackageManager.getApplicationInfo(packageName, 0) != null;\n        } catch (PackageManager.NameNotFoundException e) {\n            // Ignore\n        }\n        return false;\n    }\n\n\n    public int getSystemPid() {\n        return systemPid;\n    }\n\n    /**\n     * Process type\n     */\n    private enum ProcessType {\n        /**\n         * Server process\n         */\n        Server,\n        /**\n         * Virtual app process\n         */\n        VAppClient,\n        /**\n         * Main process\n         */\n        Main,\n        /**\n         * Child process\n         */\n        CHILD\n    }\n\n    public interface AppRequestListener {\n        void onRequestInstall(String path);\n\n        void onRequestUninstall(String pkg);\n    }\n\n    public interface OnEmitShortcutListener {\n        Bitmap getIcon(Bitmap originIcon);\n\n        String getName(String originName);\n    }\n\n    public static abstract class VirtualInitializer {\n        public void onMainProcess() {\n        }\n\n        public void onVirtualProcess() {\n        }\n\n        public void onServerProcess() {\n        }\n\n        public void onChildProcess() {\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/Constants.java",
    "content": "package com.lody.virtual.client.env;\n\nimport android.content.Intent;\n\nimport com.lody.virtual.client.stub.ShortcutHandleActivity;\nimport com.lody.virtual.helper.utils.EncodeUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * @author Lody\n *\n */\npublic class Constants {\n\n\tpublic static final String EXTRA_USER_HANDLE = \"android.intent.extra.user_handle\";\n\t/**\n\t * If an apk declared the \"fake-signature\" attribute on its Application TAG,\n\t * we will use its signature instead of the real signature.\n\t *\n\t * For more detail, please see :\n\t * https://github.com/microg/android_packages_apps_GmsCore/blob/master/\n\t * patches/android_frameworks_base-M.patch.\n\t */\n\tpublic static final String FEATURE_FAKE_SIGNATURE = \"fake-signature\";\n\tpublic static final String ACTION_PACKAGE_ADDED = \"virtual.\" + Intent.ACTION_PACKAGE_ADDED;\n\tpublic static final String ACTION_PACKAGE_REMOVED = \"virtual.\" + Intent.ACTION_PACKAGE_REMOVED;\n\tpublic static final String ACTION_PACKAGE_CHANGED = \"virtual.\" + Intent.ACTION_PACKAGE_CHANGED;\n\tpublic static final String ACTION_USER_ADDED = \"virtual.\" + \"android.intent.action.USER_ADDED\";\n\tpublic static final String ACTION_USER_REMOVED = \"virtual.\" + \"android.intent.action.USER_REMOVED\";\n\tpublic static final String ACTION_USER_INFO_CHANGED = \"virtual.\" + \"android.intent.action.USER_CHANGED\";\n\tpublic static final String ACTION_USER_STARTED = \"Virtual.\" + \"android.intent.action.USER_STARTED\";\n\tpublic static String META_KEY_IDENTITY = \"X-Identity\";\n\tpublic static String META_VALUE_STUB = \"Stub-User\";\n\n\tpublic static String NO_NOTIFICATION_FLAG = \".no_notification\";\n\tpublic static String FAKE_SIGNATURE_FLAG = \".fake_signature\";\n\n\tpublic static final String WECHAT_PACKAGE = EncodeUtils.decode(\"Y29tLnRlbmNlbnQubW0=\"); // wechat\n\tpublic static final List<String> PRIVILEGE_APP = Arrays.asList(\n\t\t\tWECHAT_PACKAGE,\n\t\t\tEncodeUtils.decode(\"Y29tLnRlbmNlbnQubW9iaWxlcXE=\")); // qq\n\n\t/**\n\t * Server process name of VA\n\t */\n\tpublic static String SERVER_PROCESS_NAME = \":x\";\n\t/**\n\t * The activity who handle the shortcut.\n\t */\n\tpublic static String SHORTCUT_PROXY_ACTIVITY_NAME = ShortcutHandleActivity.class.getName();\n\n\tpublic static final String PASS_PKG_NAME_ARGUMENT = \"MODEL_ARGUMENT\";\n\tpublic static final String PASS_KEY_INTENT = \"KEY_INTENT\";\n\tpublic static final String PASS_KEY_USER = \"KEY_USER\";\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/DeadServerException.java",
    "content": "package com.lody.virtual.client.env;\n\n/**\n * @author Lody\n */\n\npublic class DeadServerException extends RuntimeException {\n\n    public DeadServerException() {\n    }\n\n    public DeadServerException(String message) {\n        super(message);\n    }\n\n    public DeadServerException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public DeadServerException(Throwable cause) {\n        super(cause);\n    }\n\n    public DeadServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/GPSStateline.java",
    "content": "package com.lody.virtual.client.env;\n\n\nclass GPSStateline {\n    private double mAzimuth;\n    private double mElevation;\n    private boolean mHasAlmanac;\n    private boolean mHasEphemeris;\n    private int mPnr;\n    private double mSnr;\n    private boolean mUseInFix;\n\n\n    public double getAzimuth() {\n        return this.mAzimuth;\n    }\n\n    public double getElevation() {\n        return this.mElevation;\n    }\n\n    public int getPnr() {\n        return this.mPnr;\n    }\n\n    public double getSnr() {\n        return this.mSnr;\n    }\n\n    public boolean isHasAlmanac() {\n        return this.mHasAlmanac;\n    }\n\n    public boolean isHasEphemeris() {\n        return this.mHasEphemeris;\n    }\n\n    public boolean isUseInFix() {\n        return this.mUseInFix;\n    }\n\n    public void setAzimuth(double azimuth) {\n        this.mAzimuth = azimuth;\n    }\n\n    public void setElevation(double elevation) {\n        this.mElevation = elevation;\n    }\n\n    public void setHasAlmanac(boolean hasAlmanac) {\n        this.mHasAlmanac = hasAlmanac;\n    }\n\n    public void setHasEphemeris(boolean hasEphemeris) {\n        this.mHasEphemeris = hasEphemeris;\n    }\n\n    public void setPnr(int pnr) {\n        this.mPnr = pnr;\n    }\n\n    public void setSnr(double snr) {\n        this.mSnr = snr;\n    }\n\n    public void setUseInFix(boolean useInFix) {\n        this.mUseInFix = useInFix;\n    }\n\n    public GPSStateline(int pnr, double snr, double elevation, double azimuth, boolean useInFix, boolean hasAlmanac, boolean hasEphemeris) {\n        this.mPnr = pnr;\n        this.mSnr = snr;\n        this.mElevation = elevation;\n        this.mAzimuth = azimuth;\n        this.mUseInFix = useInFix;\n        this.mHasAlmanac = hasAlmanac;\n        this.mHasEphemeris = hasEphemeris;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java",
    "content": "package com.lody.virtual.client.env;\n\nimport android.Manifest;\nimport android.app.DownloadManager;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Map;\nimport java.util.Set;\n\nimport mirror.android.webkit.IWebViewUpdateService;\nimport mirror.android.webkit.WebViewFactory;\n\n/**\n * @author Lody\n */\npublic final class SpecialComponentList {\n\n    public static class ConflictInstrumentation {\n        private static final HashSet<String> INSTRUMENTATION_CONFLICTING = new HashSet<>(2);\n\n        static {\n            INSTRUMENTATION_CONFLICTING.add(\"com.qihoo.magic\");\n            INSTRUMENTATION_CONFLICTING.add(\"com.qihoo.magic_mutiple\");\n            INSTRUMENTATION_CONFLICTING.add(\"com.facebook.katana\");\n        }\n\n        public static boolean isConflictingInstrumentation(String packageName) {\n            return INSTRUMENTATION_CONFLICTING.contains(packageName);\n        }\n    }\n\n    public static class SpecSystemComponent {\n\n        private static final HashSet<String> SPEC_SYSTEM_APP_LIST = new HashSet<>(3);\n\n        static {\n            SPEC_SYSTEM_APP_LIST.add(\"android\");\n            SPEC_SYSTEM_APP_LIST.add(\"com.google.android.webview\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                try {\n                    String webViewPkgN = IWebViewUpdateService.getCurrentWebViewPackageName.call(WebViewFactory.getUpdateService.call());\n                    if (webViewPkgN != null) {\n                        SPEC_SYSTEM_APP_LIST.add(webViewPkgN);\n                    }\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        public static boolean isSpecSystemPackage(String pkg) {\n            return SPEC_SYSTEM_APP_LIST.contains(pkg);\n        }\n    }\n\n    private static final List<String> ACTION_BLACK_LIST = new ArrayList<String>(1);\n    private static final Map<String, String> PROTECTED_ACTION_MAP = new HashMap<>(5);\n    private static final HashSet<String> WHITE_PERMISSION = new HashSet<>(3);\n    private static final Set<String> SYSTEM_BROADCAST_ACTION = new HashSet<>(7);\n    private static String PROTECT_ACTION_PREFIX = \"_VA_protected_\";\n\n    static {\n        SYSTEM_BROADCAST_ACTION.add(DownloadManager.ACTION_DOWNLOAD_COMPLETE);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_SCREEN_ON);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_SCREEN_OFF);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_NEW_OUTGOING_CALL);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_TIME_TICK);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_TIME_CHANGED);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_TIMEZONE_CHANGED);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_BATTERY_CHANGED);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_BATTERY_LOW);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_BATTERY_OKAY);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_POWER_CONNECTED);\n        SYSTEM_BROADCAST_ACTION.add(Intent.ACTION_POWER_DISCONNECTED);\n        SYSTEM_BROADCAST_ACTION.add(\"android.provider.Telephony.SMS_RECEIVED\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.provider.Telephony.SMS_DELIVER\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.net.wifi.STATE_CHANGE\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.net.wifi.SCAN_RESULTS\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.net.wifi.WIFI_STATE_CHANGED\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.net.conn.CONNECTIVITY_CHANGE\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.intent.action.ANY_DATA_STATE\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.intent.action.SIM_STATE_CHANGED\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.location.PROVIDERS_CHANGED\");\n        SYSTEM_BROADCAST_ACTION.add(\"android.location.MODE_CHANGED\");\n\n        ACTION_BLACK_LIST.add(\"android.appwidget.action.APPWIDGET_UPDATE\");\n\n        WHITE_PERMISSION.add(\"com.google.android.gms.settings.SECURITY_SETTINGS\");\n        WHITE_PERMISSION.add(\"com.google.android.apps.plus.PRIVACY_SETTINGS\");\n        WHITE_PERMISSION.add(Manifest.permission.ACCOUNT_MANAGER);\n\n        PROTECTED_ACTION_MAP.put(Intent.ACTION_PACKAGE_ADDED, Constants.ACTION_PACKAGE_ADDED);\n        PROTECTED_ACTION_MAP.put(Intent.ACTION_PACKAGE_REMOVED, Constants.ACTION_PACKAGE_REMOVED);\n        PROTECTED_ACTION_MAP.put(Intent.ACTION_PACKAGE_CHANGED, Constants.ACTION_PACKAGE_CHANGED);\n        PROTECTED_ACTION_MAP.put(\"android.intent.action.USER_ADDED\", Constants.ACTION_USER_ADDED);\n        PROTECTED_ACTION_MAP.put(\"android.intent.action.USER_REMOVED\", Constants.ACTION_USER_REMOVED);\n\n    }\n\n\n\n    /**\n     * Check if the action in the BlackList.\n     *\n     * @param action Action\n     */\n    public static boolean isActionInBlackList(String action) {\n        return ACTION_BLACK_LIST.contains(action);\n    }\n\n    /**\n     * Add an action to the BlackList.\n     *\n     * @param action action\n     */\n    public static void addBlackAction(String action) {\n        ACTION_BLACK_LIST.add(action);\n    }\n\n    public static void protectIntentFilter(IntentFilter filter) {\n        if (filter != null) {\n            List<String> actions = mirror.android.content.IntentFilter.mActions.get(filter);\n            ListIterator<String> iterator = actions.listIterator();\n            while (iterator.hasNext()) {\n                String action = iterator.next();\n                if (SpecialComponentList.isActionInBlackList(action)) {\n                    iterator.remove();\n                    continue;\n                }\n                if (SYSTEM_BROADCAST_ACTION.contains(action)) {\n                    continue;\n                }\n                String newAction = SpecialComponentList.protectAction(action);\n                if (newAction != null) {\n                    iterator.set(newAction);\n                }\n            }\n        }\n    }\n\n    public static void protectIntent(Intent intent) {\n        String protectAction = protectAction(intent.getAction());\n        if (protectAction != null) {\n            intent.setAction(protectAction);\n        }\n    }\n\n    public static void unprotectIntent(Intent intent) {\n        String unprotectAction = unprotectAction(intent.getAction());\n        if (unprotectAction != null) {\n            intent.setAction(unprotectAction);\n        }\n    }\n\n    public static String protectAction(String originAction) {\n        if (originAction == null) {\n            return null;\n        }\n        if (originAction.startsWith(\"_VA_\")) {\n            return originAction;\n        }\n        String newAction = PROTECTED_ACTION_MAP.get(originAction);\n        if (newAction == null) {\n            newAction = PROTECT_ACTION_PREFIX + originAction;\n        }\n        return newAction;\n    }\n\n    public static String unprotectAction(String action) {\n        if (action == null) {\n            return null;\n        }\n        if (action.startsWith(PROTECT_ACTION_PREFIX)) {\n            return action.substring(PROTECT_ACTION_PREFIX.length());\n        }\n        for (Map.Entry<String, String> next : PROTECTED_ACTION_MAP.entrySet()) {\n            String modifiedAction = next.getValue();\n            if (modifiedAction.equals(action)) {\n                return next.getKey();\n            }\n        }\n        return null;\n    }\n\n    public static boolean isWhitePermission(String permission) {\n        return WHITE_PERMISSION.contains(permission);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/VirtualGPSSatalines.java",
    "content": "package com.lody.virtual.client.env;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class VirtualGPSSatalines {\n    private static VirtualGPSSatalines INSTANCE;\n    private int mAlmanacMask;\n    private float[] mAzimuths;\n    private float[] mElevations;\n    private int mEphemerisMask;\n    private float[] mSnrs;\n    private int mUsedInFixMask;\n    private int[] pnrs;\n    private int[] prnWithFlags;\n    private int svCount;\n\n    static {\n        INSTANCE = new VirtualGPSSatalines();\n    }\n\n    public int getAlmanacMask() {\n        return this.mAlmanacMask;\n    }\n\n    public float[] getAzimuths() {\n        return this.mAzimuths;\n    }\n\n    public float[] getElevations() {\n        return this.mElevations;\n    }\n\n    public int getEphemerisMask() {\n        return this.mEphemerisMask;\n    }\n\n    public int[] getPrns() {\n        return this.pnrs;\n    }\n\n    public float[] getSnrs() {\n        return this.mSnrs;\n    }\n\n    public int getUsedInFixMask() {\n        return this.mUsedInFixMask;\n    }\n\n    public static VirtualGPSSatalines get() {\n        return INSTANCE;\n    }\n\n    private VirtualGPSSatalines() {\n        List<GPSStateline> statelines = new ArrayList<>();\n        statelines.add(new GPSStateline(5, 1.0d, 5.0d, 112.0d, false, true, true));\n        statelines.add(new GPSStateline(13, 13.5d, 23.0d, 53.0d, true, true, true));\n        statelines.add(new GPSStateline(14, 19.1d, 6.0d, 247.0d, true, true, true));\n        statelines.add(new GPSStateline(15, 31.0d, 58.0d, 45.0d, true, true, true));\n        statelines.add(new GPSStateline(18, 0.0d, 52.0d, 309.0d, false, true, true));\n        statelines.add(new GPSStateline(20, 30.1d, 54.0d, 105.0d, true, true, true));\n        statelines.add(new GPSStateline(21, 33.2d, 56.0d, 251.0d, true, true, true));\n        statelines.add(new GPSStateline(22, 0.0d, 14.0d, 299.0d, false, true, true));\n        statelines.add(new GPSStateline(24, 25.9d, 57.0d, 157.0d, true, true, true));\n        statelines.add(new GPSStateline(27, 18.0d, 3.0d, 309.0d, true, true, true));\n        statelines.add(new GPSStateline(28, 18.2d, 3.0d, 42.0d, true, true, true));\n        statelines.add(new GPSStateline(41, 28.8d, 0.0d, 0.0d, false, false, false));\n        statelines.add(new GPSStateline(50, 29.2d, 0.0d, 0.0d, false, true, true));\n        statelines.add(new GPSStateline(67, 14.4d, 2.0d, 92.0d, false, false, false));\n        statelines.add(new GPSStateline(68, 21.2d, 45.0d, 60.0d, false, false, false));\n        statelines.add(new GPSStateline(69, 17.5d, 50.0d, 330.0d, false, true, true));\n        statelines.add(new GPSStateline(70, 22.4d, 7.0d, 291.0d, false, false, false));\n        statelines.add(new GPSStateline(77, 23.8d, 10.0d, 23.0d, true, true, true));\n        statelines.add(new GPSStateline(78, 18.0d, 47.0d, 70.0d, true, true, true));\n        statelines.add(new GPSStateline(79, 22.8d, 41.0d, 142.0d, true, true, true));\n        statelines.add(new GPSStateline(83, 0.2d, 9.0d, 212.0d, false, false, false));\n        statelines.add(new GPSStateline(84, 16.7d, 30.0d, 264.0d, true, true, true));\n        statelines.add(new GPSStateline(85, 12.1d, 20.0d, 317.0d, true, true, true));\n        this.svCount = statelines.size();\n        this.pnrs = new int[statelines.size()];\n        for (int i = 0; i < statelines.size(); i++) {\n            this.pnrs[i] = statelines.get(i).getPnr();\n        }\n        this.mSnrs = new float[statelines.size()];\n        for (int i = 0; i < statelines.size(); i++) {\n            this.mSnrs[i] = (float) statelines.get(i).getSnr();\n        }\n        this.mElevations = new float[statelines.size()];\n        for (int i = 0; i < statelines.size(); i++) {\n            this.mElevations[i] = (float) statelines.get(i).getElevation();\n        }\n        this.mAzimuths = new float[statelines.size()];\n        for (int i = 0; i < statelines.size(); i++) {\n            this.mAzimuths[i] = (float) statelines.get(i).getAzimuth();\n        }\n        this.mEphemerisMask = 0;\n        for (int i = 0; i < statelines.size(); i++) {\n            if (statelines.get(i).isHasEphemeris()) {\n                this.mEphemerisMask |= 1 << (statelines.get(i).getPnr() - 1);\n            }\n        }\n        this.mAlmanacMask = 0;\n        for (int i = 0; i < statelines.size(); i++) {\n            if (statelines.get(i).isHasAlmanac()) {\n                this.mAlmanacMask |= 1 << (statelines.get(i).getPnr() - 1);\n            }\n        }\n        this.mUsedInFixMask = 0;\n        for (int i = 0; statelines.size() > i; i++) {\n            if (statelines.get(i).isUseInFix()) {\n                this.mUsedInFixMask |= 1 << (statelines.get(i).getPnr() - 1);\n            }\n        }\n        this.prnWithFlags = new int[statelines.size()];\n        for (int i = 0; i < statelines.size(); i++) {\n            GPSStateline gpsStateline = statelines.get(i);\n            this.prnWithFlags[i] =\n                    (gpsStateline.isHasEphemeris() ? 1 : 0)\n                            | (gpsStateline.isHasAlmanac() ? 1 : 0) << 1\n                            | (gpsStateline.isUseInFix() ? 1 : 0) << 2\n                            | 8\n                            | (gpsStateline.getPnr() << 7);\n        }\n    }\n\n    public int getSvCount() {\n        return this.svCount;\n    }\n\n    public int[] getPrnWithFlags() {\n        return this.prnWithFlags;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/env/VirtualRuntime.java",
    "content": "package com.lody.virtual.client.env;\n\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Process;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport mirror.android.ddm.DdmHandleAppName;\nimport mirror.android.ddm.DdmHandleAppNameJBMR1;\n\n/**\n * @author Lody\n *         <p>\n *         <p/>\n *         Runtime Environment for App.\n */\npublic class VirtualRuntime {\n\n    private static final Handler sUIHandler = new Handler(Looper.getMainLooper());\n\n    private static String sInitialPackageName;\n    private static String sProcessName;\n\n    public static Handler getUIHandler() {\n        return sUIHandler;\n    }\n\n    public static String getProcessName() {\n        return sProcessName;\n    }\n\n    public static String getInitialPackageName() {\n        return sInitialPackageName;\n    }\n\n    public static void setupRuntime(String processName, ApplicationInfo appInfo) {\n        if (sProcessName != null) {\n            return;\n        }\n        sInitialPackageName = appInfo.packageName;\n        sProcessName = processName;\n        mirror.android.os.Process.setArgV0.call(processName);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            DdmHandleAppNameJBMR1.setAppName.call(processName, 0);\n        } else {\n            DdmHandleAppName.setAppName.call(processName);\n        }\n    }\n\n    public static <T> T crash(RemoteException e) throws RuntimeException {\n        e.printStackTrace();\n        if (VirtualCore.get().isVAppProcess()) {\n            Process.killProcess(Process.myPid());\n            System.exit(0);\n        }\n        throw new DeadServerException(e);\n    }\n\n\n    public static boolean isArt() {\n        return System.getProperty(\"java.vm.version\").startsWith(\"2\");\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/fixer/ActivityFixer.java",
    "content": "package com.lody.virtual.client.fixer;\n\nimport android.app.Activity;\nimport android.app.ActivityManager;\nimport android.app.WallpaperManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\n\nimport mirror.com.android.internal.R_Hide;\n\n/**\n * @author Lody\n *\n */\npublic final class ActivityFixer {\n\n\tprivate ActivityFixer() {\n\t}\n\n\tpublic static void fixActivity(Activity activity) {\n\t\tContext baseContext = activity.getBaseContext();\n\t\ttry {\n\t\t\tTypedArray typedArray = activity.obtainStyledAttributes((R_Hide.styleable.Window.get()));\n\t\t\tif (typedArray != null) {\n\t\t\t\tboolean showWallpaper = typedArray.getBoolean(R_Hide.styleable.Window_windowShowWallpaper.get(),\n\t\t\t\t\t\tfalse);\n\t\t\t\tif (showWallpaper) {\n\t\t\t\t\tactivity.getWindow().setBackgroundDrawable(WallpaperManager.getInstance(activity).getDrawable());\n\t\t\t\t}\n\t\t\t\ttypedArray.recycle();\n\t\t\t}\n\t\t} catch (Throwable e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n\t\t\tIntent intent = activity.getIntent();\n\t\t\tApplicationInfo applicationInfo = baseContext.getApplicationInfo();\n\t\t\tPackageManager pm = activity.getPackageManager();\n\t\t\tif (intent != null && activity.isTaskRoot()) {\n\t\t\t\ttry {\n\t\t\t\t\tString label = applicationInfo.loadLabel(pm) + \"\";\n\t\t\t\t\tBitmap icon = null;\n\t\t\t\t\tDrawable drawable = applicationInfo.loadIcon(pm);\n\t\t\t\t\tif (drawable instanceof BitmapDrawable) {\n\t\t\t\t\t\ticon = ((BitmapDrawable) drawable).getBitmap();\n\t\t\t\t\t}\n\t\t\t\t\tactivity.setTaskDescription(new ActivityManager.TaskDescription(label, icon));\n\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/fixer/ComponentFixer.java",
    "content": "package com.lody.virtual.client.fixer;\n\nimport android.content.pm.ComponentInfo;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.server.pm.PackageSetting;\n\n/**\n * @author Lody\n */\n\npublic class ComponentFixer {\n\n    public static String fixComponentClassName(String pkgName, String className) {\n        if (className != null) {\n            if (className.charAt(0) == '.') {\n                return pkgName + className;\n            }\n            return className;\n        }\n        return null;\n    }\n\n    public static void fixComponentInfo(PackageSetting setting, ComponentInfo info, int userId) {\n        if (info != null) {\n            if (TextUtils.isEmpty(info.processName)) {\n                info.processName = info.packageName;\n            }\n            info.name = fixComponentClassName(info.packageName, info.name);\n            if (info.processName == null) {\n                info.processName = info.applicationInfo.processName;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/fixer/ContextFixer.java",
    "content": "package com.lody.virtual.client.fixer;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.os.Build;\nimport android.os.DropBoxManager;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.InvocationStubManager;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationStub;\nimport com.lody.virtual.client.hook.proxies.dropbox.DropBoxManagerStub;\nimport com.lody.virtual.client.hook.proxies.graphics.GraphicsStatsStub;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.ReflectException;\n\nimport mirror.android.app.ContextImpl;\nimport mirror.android.app.ContextImplKitkat;\nimport mirror.android.content.ContentResolverJBMR2;\n\n/**\n * @author Lody\n */\npublic class ContextFixer {\n\n    private static final String TAG = ContextFixer.class.getSimpleName();\n\n    /**\n     * Fuck AppOps\n     *\n     * @param context Context\n     */\n    public static void fixContext(Context context) {\n        try {\n            context.getPackageName();\n        } catch (Throwable e) {\n            return;\n        }\n        InvocationStubManager.getInstance().checkEnv(GraphicsStatsStub.class);\n        int deep = 0;\n        while (context instanceof ContextWrapper) {\n            context = ((ContextWrapper) context).getBaseContext();\n            deep++;\n            if (deep >= 10) {\n                return;\n            }\n        }\n        ContextImpl.mPackageManager.set(context, null);\n        try {\n            context.getPackageManager();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        if (!VirtualCore.get().isVAppProcess()) {\n            return;\n        }\n        DropBoxManager dm = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);\n        BinderInvocationStub boxBinder = InvocationStubManager.getInstance().getInvocationStub(DropBoxManagerStub.class);\n        if (boxBinder != null) {\n            try {\n                Reflect.on(dm).set(\"mService\", boxBinder.getProxyInterface());\n            } catch (ReflectException e) {\n                e.printStackTrace();\n            }\n        }\n        String hostPkg = VirtualCore.get().getHostPkg();\n        ContextImpl.mBasePackageName.set(context, hostPkg);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            ContextImplKitkat.mOpPackageName.set(context, hostPkg);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            ContentResolverJBMR2.mPackageName.set(context.getContentResolver(), hostPkg);\n        }\n\n        if (ContextImpl.getAttributionSource != null) {\n            fixAttributionSource(ContextImpl.getAttributionSource.call(context), hostPkg, VClientImpl.get().getVUid());\n        }\n    }\n\n    public static void fixAttributionSource(Object attr, String pkg, int uid) {\n        if (attr == null) {\n            return;\n        }\n        try {\n            Object mAttributionSourceState = Reflect.on(attr).get(\"mAttributionSourceState\");\n            Reflect.on(mAttributionSourceState).set(\"uid\", uid);\n            Reflect.on(mAttributionSourceState).set(\"packageName\", pkg);\n\n            Object next = Reflect.on(attr).call(\"getNext\").get();\n            fixAttributionSource(next, pkg, uid);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/BinderInvocationProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefStaticMethod;\nimport mirror.android.os.ServiceManager;\n\n/**\n * @author Paulo Costa\n *\n * @see MethodInvocationProxy\n */\npublic abstract class BinderInvocationProxy extends MethodInvocationProxy<BinderInvocationStub> {\n\n\tprotected String mServiceName;\n\n\tpublic BinderInvocationProxy(IInterface stub, String serviceName) {\n\t\tthis(new BinderInvocationStub(stub), serviceName);\n\t}\n\n\tpublic BinderInvocationProxy(RefStaticMethod<IInterface> asInterfaceMethod, String serviceName) {\n\t\tthis(new BinderInvocationStub(asInterfaceMethod, ServiceManager.getService.call(serviceName)), serviceName);\n\t}\n\n\tpublic BinderInvocationProxy(Class<?> stubClass, String serviceName) {\n\t\tthis(new BinderInvocationStub(stubClass, ServiceManager.getService.call(serviceName)), serviceName);\n\t}\n\n\tpublic BinderInvocationProxy(BinderInvocationStub hookDelegate, String serviceName) {\n\t\tsuper(hookDelegate);\n\t\tthis.mServiceName = serviceName;\n\t}\n\n\t@Override\n\tpublic void inject() throws Throwable {\n\t\tgetInvocationStub().replaceService(mServiceName);\n\t}\n\n\t@Override\n\tpublic boolean isEnvBad() {\n\t\tIBinder binder = ServiceManager.getService.call(mServiceName);\n\t\treturn binder != null && getInvocationStub() != binder;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/BinderInvocationStub.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport java.io.FileDescriptor;\nimport java.lang.reflect.Method;\n\nimport mirror.RefStaticMethod;\nimport mirror.android.os.ServiceManager;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"unchecked\")\npublic class BinderInvocationStub extends MethodInvocationStub<IInterface> implements IBinder {\n\n    private static final String TAG = BinderInvocationStub.class.getSimpleName();\n    private IBinder mBaseBinder;\n\n    public BinderInvocationStub(RefStaticMethod<IInterface> asInterfaceMethod, IBinder binder) {\n        this(asInterface(asInterfaceMethod, binder));\n    }\n\n    public BinderInvocationStub(Class<?> stubClass, IBinder binder) {\n        this(asInterface(stubClass, binder));\n    }\n\n\n    public BinderInvocationStub(IInterface mBaseInterface) {\n        super(mBaseInterface);\n        mBaseBinder = getBaseInterface() != null ? getBaseInterface().asBinder() : null;\n        addMethodProxy(new AsBinder());\n    }\n\n    private static IInterface asInterface(RefStaticMethod<IInterface> asInterfaceMethod, IBinder binder) {\n        if (asInterfaceMethod == null || binder == null) {\n            return null;\n        }\n        return asInterfaceMethod.call(binder);\n    }\n\n    private static IInterface asInterface(Class<?> stubClass, IBinder binder) {\n        try {\n            if (stubClass == null || binder == null) {\n                return null;\n            }\n            Method asInterface = stubClass.getMethod(\"asInterface\", IBinder.class);\n            return (IInterface) asInterface.invoke(null, binder);\n        } catch (Exception e) {\n            Log.d(TAG, \"Could not create stub \" + stubClass.getName() + \". Cause: \" + e);\n            return null;\n        }\n    }\n\n    public void replaceService(String name) {\n        if (mBaseBinder != null) {\n            ServiceManager.sCache.get().put(name, this);\n        }\n    }\n\n    private final class AsBinder extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"asBinder\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return BinderInvocationStub.this;\n        }\n    }\n\n\n    @Override\n    public String getInterfaceDescriptor() throws RemoteException {\n        return mBaseBinder.getInterfaceDescriptor();\n    }\n\n    public Context getContext() {\n        return VirtualCore.get().getContext();\n    }\n\n    @Override\n    public boolean pingBinder() {\n        return mBaseBinder.pingBinder();\n    }\n\n    @Override\n    public boolean isBinderAlive() {\n        return mBaseBinder.isBinderAlive();\n    }\n\n    @Override\n    public IInterface queryLocalInterface(String descriptor) {\n        return getProxyInterface();\n    }\n\n    @Override\n    public void dump(FileDescriptor fd, String[] args) throws RemoteException {\n        mBaseBinder.dump(fd, args);\n    }\n\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)\n    @Override\n    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {\n        mBaseBinder.dumpAsync(fd, args);\n    }\n\n    @Override\n    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        return mBaseBinder.transact(code, data, reply, flags);\n    }\n\n    @Override\n    public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {\n        mBaseBinder.linkToDeath(recipient, flags);\n    }\n\n    @Override\n    public boolean unlinkToDeath(DeathRecipient recipient, int flags) {\n        return mBaseBinder.unlinkToDeath(recipient, flags);\n    }\n\n    public IBinder getBaseBinder() {\n        return mBaseBinder;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/Inject.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author Lody\n *\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Inject {\n\tClass<?> value();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/LogInvocation.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.util.Log;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Add this annotation to a {@link MethodProxy} or a {@link MethodInvocationStub} to\n * log all the calls and their arguments.\n *\n * Obviously, this is only useful for debugging.\n */\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface LogInvocation {\n    public Condition value() default Condition.ALWAYS;\n\n    static enum Condition {\n        /** Never logs anything */\n        NEVER {\n            public int getLogLevel(boolean isHooked, boolean isError) {\n                return -1;\n            }\n        },\n        /**\n         * Logs every call.\n         * Mostly useful for debugging.\n         */\n        ALWAYS {\n            public int getLogLevel(boolean isHooked, boolean isError) {\n                return isError ? Log.WARN : Log.INFO;\n            }\n        },\n        /**\n         * Logs only calls that exited with error\n         * A reasonable tradeoff between noise and getting relevant information\n         */\n        ON_ERROR {\n            public int getLogLevel(boolean isHooked, boolean isError) {\n                return isError ? Log.WARN : -1;\n            }\n        },\n\n        /**\n         *  Log only calls that haven't been hooked\n         *  It only makes sense on a MethodInvocationProxy, and is useful to pinpoint missing methods\n         */\n        NOT_HOOKED {\n            public int getLogLevel(boolean isHooked, boolean isError) {\n                return isHooked ? -1 : isError ? Log.WARN : Log.INFO;\n            }\n        };\n\n        public abstract int getLogLevel(boolean isHooked, boolean isError);\n    };\n};\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/MethodBox.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\n@SuppressWarnings(\"unchecked\")\npublic class MethodBox {\n    public final Method method;\n    public final Object who;\n    public final Object[] args;\n\n    public MethodBox(Method method, Object who, Object[] args) {\n        this.method = method;\n        this.who = who;\n        this.args = args;\n    }\n\n    public <T> T call() throws InvocationTargetException {\n        try {\n            return (T) method.invoke(who, args);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public <T> T callSafe() {\n        try {\n            return (T) method.invoke(who, args);\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        } catch (InvocationTargetException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/MethodInvocationProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.core.InvocationStubManager;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.interfaces.IInjector;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Modifier;\n\n/**\n * @author Lody\n *         <p>\n *         This class is responsible with:\n *         - Instantiating a {@link MethodInvocationStub.HookInvocationHandler} on {@link #getInvocationStub()} ()}\n *         - Install a bunch of {@link MethodProxy}s, either with a @{@link Inject} annotation or manually\n *         calling {@link #addMethodProxy(MethodProxy)} from {@link #onBindMethods()}\n *         - Install the hooked object on the Runtime via {@link #inject()}\n *         <p>\n *         All {@link MethodInvocationProxy}s (plus a couple of other @{@link IInjector}s are installed by\n *         {@link InvocationStubManager}\n * @see Inject\n */\npublic abstract class MethodInvocationProxy<T extends MethodInvocationStub> implements IInjector {\n\n    protected T mInvocationStub;\n\n    public MethodInvocationProxy(T invocationStub) {\n        this.mInvocationStub = invocationStub;\n        onBindMethods();\n        afterHookApply(invocationStub);\n\n        LogInvocation loggingAnnotation = getClass().getAnnotation(LogInvocation.class);\n        if (loggingAnnotation != null) {\n            invocationStub.setInvocationLoggingCondition(loggingAnnotation.value());\n        }\n    }\n\n    protected void onBindMethods() {\n\n        if (mInvocationStub == null) {\n            return;\n        }\n        Class<? extends MethodInvocationProxy> clazz = getClass();\n        Inject inject = clazz.getAnnotation(Inject.class);\n        if (inject != null) {\n            Class<?> proxiesClass = inject.value();\n            Class<?>[] innerClasses = proxiesClass.getDeclaredClasses();\n            for (Class<?> innerClass : innerClasses) {\n                if (!Modifier.isAbstract(innerClass.getModifiers())\n                        && MethodProxy.class.isAssignableFrom(innerClass)\n                        && innerClass.getAnnotation(SkipInject.class) == null) {\n                    addMethodProxy(innerClass);\n                }\n            }\n\n        }\n    }\n\n    private void addMethodProxy(Class<?> hookType) {\n        try {\n            Constructor<?> constructor = hookType.getDeclaredConstructors()[0];\n            if (!constructor.isAccessible()) {\n                constructor.setAccessible(true);\n            }\n            MethodProxy methodProxy;\n            if (constructor.getParameterTypes().length == 0) {\n                methodProxy = (MethodProxy) constructor.newInstance();\n            } else {\n                methodProxy = (MethodProxy) constructor.newInstance(this);\n            }\n            mInvocationStub.addMethodProxy(methodProxy);\n        } catch (Throwable e) {\n            throw new RuntimeException(\"Unable to instance Hook : \" + hookType + \" : \" + e.getMessage());\n        }\n    }\n\n    public MethodProxy addMethodProxy(MethodProxy methodProxy) {\n        return mInvocationStub.addMethodProxy(methodProxy);\n    }\n\n    protected void afterHookApply(T delegate) {\n    }\n\n    @Override\n    public abstract void inject() throws Throwable;\n\n    public Context getContext() {\n        return VirtualCore.get().getContext();\n    }\n\n    public T getInvocationStub() {\n        return mInvocationStub;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/MethodInvocationStub.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n *         <p>\n *         HookHandler uses Java's {@link Proxy} to create a wrapper for existing services.\n *         <p>\n *         When any method is called on the wrapper, it checks if there is any {@link MethodProxy} registered\n *         and enabled for that method. If so, it calls the startUniformer instead of the wrapped implementation.\n *         <p>\n *         The whole thing is managed by a {@link MethodInvocationProxy} subclass\n */\n@SuppressWarnings(\"unchecked\")\npublic class MethodInvocationStub<T> {\n\n    private static final String TAG = MethodInvocationStub.class.getSimpleName();\n\n    private Map<String, MethodProxy> mInternalMethodProxies = new HashMap<>();\n    private T mBaseInterface;\n    private T mProxyInterface;\n    private String mIdentityName;\n    private LogInvocation.Condition mInvocationLoggingCondition = LogInvocation.Condition.NEVER;\n\n\n    public Map<String, MethodProxy> getAllHooks() {\n        return mInternalMethodProxies;\n    }\n\n\n    public MethodInvocationStub(T baseInterface, Class<?>... proxyInterfaces) {\n        this.mBaseInterface = baseInterface;\n        if (baseInterface != null) {\n            if (proxyInterfaces == null) {\n                proxyInterfaces = MethodParameterUtils.getAllInterface(baseInterface.getClass());\n            }\n            mProxyInterface = (T) Proxy.newProxyInstance(baseInterface.getClass().getClassLoader(), proxyInterfaces, new HookInvocationHandler());\n        } else {\n            VLog.w(TAG, \"Unable to build HookDelegate: %s.\", getIdentityName());\n        }\n    }\n\n    public LogInvocation.Condition getInvocationLoggingCondition() {\n        return mInvocationLoggingCondition;\n    }\n\n    public void setInvocationLoggingCondition(LogInvocation.Condition invocationLoggingCondition) {\n        mInvocationLoggingCondition = invocationLoggingCondition;\n    }\n\n    public void setIdentityName(String identityName) {\n        this.mIdentityName = identityName;\n    }\n\n    public String getIdentityName() {\n        if (mIdentityName != null) {\n            return mIdentityName;\n        }\n        return getClass().getSimpleName();\n    }\n\n    public MethodInvocationStub(T baseInterface) {\n        this(baseInterface, (Class[]) null);\n    }\n\n    /**\n     * Copy all proxies from the input HookDelegate.\n     *\n     * @param from the HookDelegate we copy from.\n     */\n    public void copyMethodProxies(MethodInvocationStub from) {\n        this.mInternalMethodProxies.putAll(from.getAllHooks());\n    }\n\n    /**\n     * Add a method proxy.\n     *\n     * @param methodProxy proxy\n     */\n    public MethodProxy addMethodProxy(MethodProxy methodProxy) {\n        if (methodProxy != null && !TextUtils.isEmpty(methodProxy.getMethodName())) {\n            if (mInternalMethodProxies.containsKey(methodProxy.getMethodName())) {\n                VLog.w(TAG, \"The Hook(%s, %s) you added has been in existence.\", methodProxy.getMethodName(),\n                        methodProxy.getClass().getName());\n                return methodProxy;\n            }\n            mInternalMethodProxies.put(methodProxy.getMethodName(), methodProxy);\n        }\n        return methodProxy;\n    }\n\n    /**\n     * Remove a method proxy.\n     *\n     * @param hookName proxy\n     * @return The proxy you removed\n     */\n    public MethodProxy removeMethodProxy(String hookName) {\n        return mInternalMethodProxies.remove(hookName);\n    }\n\n    /**\n     * Remove a method proxy.\n     *\n     * @param methodProxy target proxy\n     */\n    public void removeMethodProxy(MethodProxy methodProxy) {\n        if (methodProxy != null) {\n            removeMethodProxy(methodProxy.getMethodName());\n        }\n    }\n\n    /**\n     * Remove all method proxies.\n     */\n    public void removeAllMethodProxies() {\n        mInternalMethodProxies.clear();\n    }\n\n    /**\n     * Get the startUniformer by its name.\n     *\n     * @param name name of the Hook\n     * @param <H>  Type of the Hook\n     * @return target startUniformer\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <H extends MethodProxy> H getMethodProxy(String name) {\n        return (H) mInternalMethodProxies.get(name);\n    }\n\n    /**\n     * @return Proxy interface\n     */\n    public T getProxyInterface() {\n        return mProxyInterface;\n    }\n\n    /**\n     * @return Origin Interface\n     */\n    public T getBaseInterface() {\n        return mBaseInterface;\n    }\n\n    /**\n     * @return count of the hooks\n     */\n    public int getMethodProxiesCount() {\n        return mInternalMethodProxies.size();\n    }\n\n    private class HookInvocationHandler implements InvocationHandler {\n        @Override\n        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n            MethodProxy methodProxy = getMethodProxy(method.getName());\n            boolean useProxy = (methodProxy != null && methodProxy.isEnable());\n            boolean mightLog = (mInvocationLoggingCondition != LogInvocation.Condition.NEVER) ||\n                    (methodProxy != null && methodProxy.getInvocationLoggingCondition() != LogInvocation.Condition.NEVER);\n\n            String argStr = null;\n            Object res = null;\n            Throwable exception = null;\n            if (mightLog) {\n                // Arguments to string is done before the method is called because the method might actually change it\n                argStr = Arrays.toString(args);\n                argStr = argStr.substring(1, argStr.length()-1);\n            }\n\n\n            try {\n                if (useProxy && methodProxy.beforeCall(mBaseInterface, method, args)) {\n                    res = methodProxy.call(mBaseInterface, method, args);\n                    res = methodProxy.afterCall(mBaseInterface, method, args, res);\n                } else {\n                    res = method.invoke(mBaseInterface, args);\n                }\n                return res;\n\n            } catch (Throwable t) {\n                exception = t;\n                if (exception instanceof InvocationTargetException && ((InvocationTargetException) exception).getTargetException() != null) {\n                    exception = ((InvocationTargetException) exception).getTargetException();\n                }\n                throw exception;\n\n            } finally {\n                if (mightLog) {\n                    int logPriority = mInvocationLoggingCondition.getLogLevel(useProxy, exception != null);\n                    if (methodProxy != null) {\n                        logPriority = Math.max(logPriority, methodProxy.getInvocationLoggingCondition().getLogLevel(useProxy, exception != null));\n                    }\n                    if (logPriority >= 0) {\n                        String retString;\n                        if (exception != null) {\n                            retString = exception.toString();\n                        } else if (method.getReturnType().equals(void.class)) {\n                            retString = \"void\";\n                        } else {\n                            retString = String.valueOf(res);\n                        }\n\n                        Log.println(logPriority, TAG, method.getDeclaringClass().getSimpleName() + \".\" + method.getName() + \"(\" + argStr + \") => \" + retString);\n                    }\n                }\n            }\n        }\n    }\n\n    private void dumpMethodProxies() {\n        StringBuilder sb = new StringBuilder(50);\n        sb.append(\"*********************\");\n        for (MethodProxy proxy : mInternalMethodProxies.values()) {\n            sb.append(proxy.getMethodName()).append(\"\\n\");\n        }\n        sb.append(\"*********************\");\n        VLog.e(TAG, sb.toString());\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/MethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.VDeviceInfo;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\npublic abstract class MethodProxy {\n\n    private boolean enable = true;\n    private LogInvocation.Condition mInvocationLoggingCondition = LogInvocation.Condition.NEVER; // Inherit\n\n    public MethodProxy() {\n        LogInvocation loggingAnnotation = getClass().getAnnotation(LogInvocation.class);\n        if (loggingAnnotation != null) {\n            this.mInvocationLoggingCondition = loggingAnnotation.value();\n        }\n    }\n\n    public static String getHostPkg() {\n        return VirtualCore.get().getHostPkg();\n    }\n\n    public static String getAppPkg() {\n        return VClientImpl.get().getCurrentPackage();\n    }\n\n    protected static Context getHostContext() {\n        return VirtualCore.get().getContext();\n    }\n\n    protected static boolean isAppProcess() {\n        return VirtualCore.get().isVAppProcess();\n    }\n\n    protected static boolean isServerProcess() {\n        return VirtualCore.get().isServerProcess();\n    }\n\n    protected static boolean isMainProcess() {\n        return VirtualCore.get().isMainProcess();\n    }\n\n    protected static int getVUid() {\n        return VClientImpl.get().getVUid();\n    }\n\n    public static int getAppUserId() {\n        return VUserHandle.getUserId(getVUid());\n    }\n\n    protected static int getBaseVUid() {\n        return VClientImpl.get().getBaseVUid();\n    }\n\n    protected static int getRealUid() {\n        return VirtualCore.get().myUid();\n    }\n\n    protected static VDeviceInfo getDeviceInfo() {\n        return VClientImpl.get().getDeviceInfo();\n    }\n\n    protected static boolean isFakeLocationEnable() {\n        return VirtualLocationManager.get().getMode(VUserHandle.myUserId(), VClientImpl.get().getCurrentPackage()) != 0;\n    }\n\n    public static boolean isVisiblePackage(ApplicationInfo info) {\n        return getHostPkg().equals(info.packageName)\n                || ComponentUtils.isSystemApp(info)\n                || VirtualCore.get().isOutsidePackageVisible(info.packageName);\n    }\n\n    public abstract String getMethodName();\n\n    public boolean beforeCall(Object who, Method method, Object... args) {\n        return true;\n    }\n\n    public Object call(Object who, Method method, Object... args) throws Throwable {\n        return method.invoke(who, args);\n    }\n\n    public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n        return result;\n    }\n\n    public boolean isEnable() {\n        return enable;\n    }\n\n    public void setEnable(boolean enable) {\n        this.enable = enable;\n    }\n\n    public LogInvocation.Condition getInvocationLoggingCondition() {\n        return mInvocationLoggingCondition;\n    }\n\n    public void setInvocationloggingCondition(LogInvocation.Condition invocationLoggingCondition) {\n        mInvocationLoggingCondition = invocationLoggingCondition;\n    }\n\n    public boolean isAppPkg(String pkg) {\n        return VirtualCore.get().isAppInstalled(pkg);\n    }\n\n    protected PackageManager getPM() {\n        return VirtualCore.getPM();\n    }\n\n    @Override\n    public String toString() {\n        return \"Method : \" + getMethodName();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceCallingPkgMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\n\n/**\n * @author Lody\n */\n\npublic class ReplaceCallingPkgMethodProxy extends StaticMethodProxy {\n\n\tpublic ReplaceCallingPkgMethodProxy(String name) {\n\t\tsuper(name);\n\t}\n\n\t@Override\n\tpublic boolean beforeCall(Object who, Method method, Object... args) {\n\t\tMethodParameterUtils.replaceFirstAppPkg(args);\n\t\treturn super.beforeCall(who, method, args);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceLastPkgMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\n\n/**\n * @author Lody\n */\n\npublic class ReplaceLastPkgMethodProxy extends StaticMethodProxy {\n\n\tpublic ReplaceLastPkgMethodProxy(String name) {\n\t\tsuper(name);\n\t}\n\n\t@Override\n\tpublic boolean beforeCall(Object who, Method method, Object... args) {\n\t\tMethodParameterUtils.replaceLastAppPkg(args);\n\t\treturn super.beforeCall(who, method, args);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceLastUidMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport android.os.Process;\n\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.lang.reflect.Method;\n\npublic class ReplaceLastUidMethodProxy extends StaticMethodProxy {\n\n    public ReplaceLastUidMethodProxy(String name) {\n        super(name);\n    }\n\n    @Override\n    public boolean beforeCall(Object who, Method method, Object... args) {\n        int index = ArrayUtils.indexOfLast(args, Integer.class);\n        if (index != -1) {\n            int uid = (int) args[index];\n            if (uid == Process.myUid()) {\n                args[index] = getRealUid();\n            }\n        }\n        return super.beforeCall(who, method, args);\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceSequencePkgMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\n\n/**\n * @author Lody\n */\n\npublic class ReplaceSequencePkgMethodProxy extends StaticMethodProxy {\n\n\tprivate int sequence;\n\n\tpublic ReplaceSequencePkgMethodProxy(String name, int sequence) {\n\t\tsuper(name);\n\t\tthis.sequence = sequence;\n\t}\n\n\t@Override\n\tpublic boolean beforeCall(Object who, Method method, Object... args) {\n\t\tMethodParameterUtils.replaceSequenceAppPkg(args, sequence);\n\t\treturn super.beforeCall(who, method, args);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceSpecPkgMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\npublic class ReplaceSpecPkgMethodProxy extends StaticMethodProxy {\n\n\tprivate int index;\n\n\tpublic ReplaceSpecPkgMethodProxy(String name, int index) {\n\t\tsuper(name);\n\t\tthis.index = index;\n\t}\n\n\t@Override\n\tpublic boolean beforeCall(Object who, Method method, Object... args) {\n\t\tif (args != null) {\n\t\t\tint i = index;\n\t\t\tif (i < 0) {\n\t\t\t\ti += args.length;\n\t\t\t}\n\t\t\tif (i >= 0 && i < args.length && args[i] instanceof String) {\n\t\t\t\targs[i] = getHostPkg();\n\t\t\t}\n\t\t}\n\t\treturn super.beforeCall(who, method, args);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ReplaceUidMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\npublic class ReplaceUidMethodProxy extends StaticMethodProxy {\n\n        private final int index;\n        public ReplaceUidMethodProxy(String name, int index) {\n            super(name);\n            this.index = index;\n        }\n\n    @Override\n    public boolean beforeCall(Object who, Method method, Object... args) {\n        int uid = (int) args[index];\n        if (uid == getVUid() || uid == getBaseVUid()) {\n            args[index] = getRealUid();\n        }\n        return super.beforeCall(who, method, args);\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/ResultStaticMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\npublic class ResultStaticMethodProxy extends StaticMethodProxy {\n\n\tObject mResult;\n\n\tpublic ResultStaticMethodProxy(String name, Object result) {\n\t\tsuper(name);\n\t\tmResult = result;\n\t}\n\n\tpublic Object getResult() {\n\t\treturn mResult;\n\t}\n\n\t@Override\n\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\treturn mResult;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/SkipInject.java",
    "content": "package com.lody.virtual.client.hook.base;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author Lody\n *\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface SkipInject {\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/base/StaticMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.base;\n\n/**\n * @author Lody\n */\n\npublic class StaticMethodProxy extends MethodProxy {\n\n\tprivate String mName;\n\n\tpublic StaticMethodProxy(String name) {\n\t\tthis.mName = name;\n\t}\n\n\t@Override\n\tpublic String getMethodName() {\n\t\treturn mName;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/delegate/AppInstrumentation.java",
    "content": "package com.lody.virtual.client.hook.delegate;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.Instrumentation;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.PersistableBundle;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.fixer.ActivityFixer;\nimport com.lody.virtual.client.fixer.ContextFixer;\nimport com.lody.virtual.client.interfaces.IInjector;\nimport com.lody.virtual.client.ipc.ActivityClientRecord;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.compat.BundleCompat;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.server.interfaces.IUiCallback;\n\nimport mirror.android.app.ActivityThread;\n\n/**\n * @author Lody\n */\npublic final class AppInstrumentation extends InstrumentationDelegate implements IInjector {\n\n    private static final String TAG = AppInstrumentation.class.getSimpleName();\n\n    private static AppInstrumentation gDefault;\n\n    private AppInstrumentation(Instrumentation base) {\n        super(base);\n    }\n\n    public static AppInstrumentation getDefault() {\n        if (gDefault == null) {\n            synchronized (AppInstrumentation.class) {\n                if (gDefault == null) {\n                    gDefault = create();\n                }\n            }\n        }\n        return gDefault;\n    }\n\n    private static AppInstrumentation create() {\n        Instrumentation instrumentation = ActivityThread.mInstrumentation.get(VirtualCore.mainThread());\n        if (instrumentation instanceof AppInstrumentation) {\n            return (AppInstrumentation) instrumentation;\n        }\n        return new AppInstrumentation(instrumentation);\n    }\n\n\n    @Override\n    public void inject() throws Throwable {\n        base = ActivityThread.mInstrumentation.get(VirtualCore.mainThread());\n        ActivityThread.mInstrumentation.set(VirtualCore.mainThread(), this);\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return !(ActivityThread.mInstrumentation.get(VirtualCore.mainThread()) instanceof AppInstrumentation);\n    }\n\n    @Override\n    public void callActivityOnCreate(Activity activity, Bundle icicle) {\n        if (icicle != null) {\n            BundleCompat.clearParcelledData(icicle);\n        }\n        VirtualCore.get().getComponentDelegate().beforeActivityCreate(activity);\n        IBinder token = mirror.android.app.Activity.mToken.get(activity);\n        ActivityClientRecord r = VActivityManager.get().getActivityRecord(token);\n        if (r != null) {\n            r.activity = activity;\n        }\n        ContextFixer.fixContext(activity);\n        ActivityFixer.fixActivity(activity);\n        ActivityInfo info = null;\n        if (r != null) {\n            info = r.info;\n        }\n        if (info != null) {\n            if (info.theme != 0) {\n                activity.setTheme(info.theme);\n            }\n            if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED\n                    && info.screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {\n                activity.setRequestedOrientation(info.screenOrientation);\n            }\n        }\n        try {\n            super.callActivityOnCreate(activity, icicle);\n        } catch (Throwable e) {\n            VLog.e(TAG, \"activity crashed when call onCreate, clearing\", e);\n            // 1. tell ui that we launched(failed)\n            Intent intent = activity.getIntent();\n            callUiCallback(intent, false);\n            // 2. finish ourself to tell AMS that do not try launch us again.\n            activity.finish();\n            // 3. rethrow\n            throw e;\n        }\n        VirtualCore.get().getComponentDelegate().afterActivityCreate(activity);\n    }\n\n    @Override\n    public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {\n        try {\n            return super.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance);\n        } catch (Throwable e) {\n            VLog.e(TAG, \"activity crashed when call newActivity, clearing\", e);\n            // 1. tell ui that we launched(failed)\n            callUiCallback(intent, false);\n            // 3. rethrow\n            throw e;\n        }\n    }\n\n    @Override\n    public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {\n        try {\n            return super.newActivity(cl, className, intent);\n        } catch (Throwable e) {\n            VLog.e(TAG, \"activity crashed when call newActivity, clearing\", e);\n            // 1. tell ui that we launched(failed)\n            callUiCallback(intent, false);\n            // 3. rethrow\n            throw e;\n        }\n    }\n\n    @Override\n    public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {\n        if (icicle != null) {\n            BundleCompat.clearParcelledData(icicle);\n        }\n        super.callActivityOnCreate(activity, icicle, persistentState);\n    }\n\n    @Override\n    public void callActivityOnResume(Activity activity) {\n        VirtualCore.get().getComponentDelegate().beforeActivityResume(activity);\n        VActivityManager.get().onActivityResumed(activity);\n        super.callActivityOnResume(activity);\n        VirtualCore.get().getComponentDelegate().afterActivityResume(activity);\n        Intent intent = activity.getIntent();\n\n        callUiCallback(intent, true);\n    }\n\n\n    @Override\n    public void callActivityOnDestroy(Activity activity) {\n        VirtualCore.get().getComponentDelegate().beforeActivityDestroy(activity);\n        super.callActivityOnDestroy(activity);\n        VirtualCore.get().getComponentDelegate().afterActivityDestroy(activity);\n    }\n\n    @Override\n    public void callActivityOnPause(Activity activity) {\n        VirtualCore.get().getComponentDelegate().beforeActivityPause(activity);\n        super.callActivityOnPause(activity);\n        VirtualCore.get().getComponentDelegate().afterActivityPause(activity);\n    }\n\n\n    @Override\n    public void callApplicationOnCreate(Application app) {\n        super.callApplicationOnCreate(app);\n    }\n\n    /**\n     * tell the ui that the activity has launched.\n     * @param intent\n     */\n    private void callUiCallback(Intent intent, boolean success) {\n        IUiCallback callback = VirtualCore.getUiCallback(intent);\n        if (callback != null) {\n            try {\n                if (success) {\n                    callback.onAppOpened(VClientImpl.get().getCurrentPackage(), VUserHandle.myUserId());\n                } else {\n                    callback.onOpenFailed(VClientImpl.get().getCurrentPackage(), VUserHandle.myUserId());\n                }\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/delegate/ComponentDelegate.java",
    "content": "package com.lody.virtual.client.hook.delegate;\n\n\nimport android.app.Application;\nimport android.content.Intent;\n\nimport android.app.Activity;\n\npublic interface ComponentDelegate {\n\n    ComponentDelegate EMPTY = new ComponentDelegate() {\n\n        @Override\n        public void beforeActivityCreate(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void beforeActivityResume(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void beforeActivityPause(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void beforeActivityDestroy(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void afterActivityCreate(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void afterActivityResume(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void afterActivityPause(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void afterActivityDestroy(Activity activity) {\n            // Empty\n        }\n\n        @Override\n        public void onSendBroadcast(Intent intent) {\n            // Empty\n        }\n\n        @Override\n        public void beforeApplicationCreate(Application application) {\n            // Empty\n        }\n\n        @Override\n        public void afterApplicationCreate(Application application) {\n            // Empty\n        }\n    };\n\n    void beforeApplicationCreate(Application application);\n\n    void afterApplicationCreate(Application application);\n\n    void beforeActivityCreate(Activity activity);\n\n    void beforeActivityResume(Activity activity);\n\n    void beforeActivityPause(Activity activity);\n\n    void beforeActivityDestroy(Activity activity);\n\n    void afterActivityCreate(Activity activity);\n\n    void afterActivityResume(Activity activity);\n\n    void afterActivityPause(Activity activity);\n\n    void afterActivityDestroy(Activity activity);\n\n    void onSendBroadcast(Intent intent);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/delegate/InstrumentationDelegate.java",
    "content": "package com.lody.virtual.client.hook.delegate;\n\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.Instrumentation;\nimport android.app.UiAutomation;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.PersistableBundle;\nimport android.view.KeyEvent;\nimport android.view.MotionEvent;\n\n/**\n * @author Lody\n */\npublic class InstrumentationDelegate extends Instrumentation {\n\n\tprotected Instrumentation base;\n\n\tpublic InstrumentationDelegate(Instrumentation base) {\n\t\tthis.base = base;\n\t}\n\n\tpublic static Application newApplication(Class<?> clazz, Context context)\n\t\t\tthrows InstantiationException, IllegalAccessException, ClassNotFoundException {\n\t\treturn Instrumentation.newApplication(clazz, context);\n\t}\n\n\t@Override\n\tpublic void onCreate(Bundle arguments) {\n\t\tbase.onCreate(arguments);\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tbase.start();\n\t}\n\n\t@Override\n\tpublic void onStart() {\n\t\tbase.onStart();\n\t}\n\n\t@Override\n\tpublic boolean onException(Object obj, Throwable e) {\n\t\treturn base.onException(obj, e);\n\t}\n\n\t@Override\n\tpublic void sendStatus(int resultCode, Bundle results) {\n\t\tbase.sendStatus(resultCode, results);\n\t}\n\n\t@Override\n\tpublic void finish(int resultCode, Bundle results) {\n\t\tbase.finish(resultCode, results);\n\t}\n\n\t@Override\n\tpublic void setAutomaticPerformanceSnapshots() {\n\t\tbase.setAutomaticPerformanceSnapshots();\n\t}\n\n\t@Override\n\tpublic void startPerformanceSnapshot() {\n\t\tbase.startPerformanceSnapshot();\n\t}\n\n\t@Override\n\tpublic void endPerformanceSnapshot() {\n\t\tbase.endPerformanceSnapshot();\n\t}\n\n\t@Override\n\tpublic void onDestroy() {\n\t\tbase.onDestroy();\n\t}\n\n\t@Override\n\tpublic Context getContext() {\n\t\treturn base.getContext();\n\t}\n\n\t@Override\n\tpublic ComponentName getComponentName() {\n\t\treturn base.getComponentName();\n\t}\n\n\t@Override\n\tpublic Context getTargetContext() {\n\t\treturn base.getTargetContext();\n\t}\n\n\t@Override\n\tpublic boolean isProfiling() {\n\t\treturn base.isProfiling();\n\t}\n\n\t@Override\n\tpublic void startProfiling() {\n\t\tbase.startProfiling();\n\t}\n\n\t@Override\n\tpublic void stopProfiling() {\n\t\tbase.stopProfiling();\n\t}\n\n\t@Override\n\tpublic void setInTouchMode(boolean inTouch) {\n\t\tbase.setInTouchMode(inTouch);\n\t}\n\n\t@Override\n\tpublic void waitForIdle(Runnable recipient) {\n\t\tbase.waitForIdle(recipient);\n\t}\n\n\t@Override\n\tpublic void waitForIdleSync() {\n\t\tbase.waitForIdleSync();\n\t}\n\n\t@Override\n\tpublic void runOnMainSync(Runnable runner) {\n\t\tbase.runOnMainSync(runner);\n\t}\n\n\t@Override\n\tpublic Activity startActivitySync(Intent intent) {\n\t\treturn base.startActivitySync(intent);\n\t}\n\n\t@Override\n\tpublic void addMonitor(ActivityMonitor monitor) {\n\t\tbase.addMonitor(monitor);\n\t}\n\n\t@Override\n\tpublic ActivityMonitor addMonitor(IntentFilter filter, ActivityResult result, boolean block) {\n\t\treturn base.addMonitor(filter, result, block);\n\t}\n\n\t@Override\n\tpublic ActivityMonitor addMonitor(String cls, ActivityResult result, boolean block) {\n\t\treturn base.addMonitor(cls, result, block);\n\t}\n\n\t@Override\n\tpublic boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {\n\t\treturn base.checkMonitorHit(monitor, minHits);\n\t}\n\n\t@Override\n\tpublic Activity waitForMonitor(ActivityMonitor monitor) {\n\t\treturn base.waitForMonitor(monitor);\n\t}\n\n\t@Override\n\tpublic Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {\n\t\treturn base.waitForMonitorWithTimeout(monitor, timeOut);\n\t}\n\n\t@Override\n\tpublic void removeMonitor(ActivityMonitor monitor) {\n\t\tbase.removeMonitor(monitor);\n\t}\n\n\t@Override\n\tpublic boolean invokeMenuActionSync(Activity targetActivity, int id, int flag) {\n\t\treturn base.invokeMenuActionSync(targetActivity, id, flag);\n\t}\n\n\t@Override\n\tpublic boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {\n\t\treturn base.invokeContextMenuAction(targetActivity, id, flag);\n\t}\n\n\t@Override\n\tpublic void sendStringSync(String text) {\n\t\tbase.sendStringSync(text);\n\t}\n\n\t@Override\n\tpublic void sendKeySync(KeyEvent event) {\n\t\tbase.sendKeySync(event);\n\t}\n\n\t@Override\n\tpublic void sendKeyDownUpSync(int key) {\n\t\tbase.sendKeyDownUpSync(key);\n\t}\n\n\t@Override\n\tpublic void sendCharacterSync(int keyCode) {\n\t\tbase.sendCharacterSync(keyCode);\n\t}\n\n\t@Override\n\tpublic void sendPointerSync(MotionEvent event) {\n\t\tbase.sendPointerSync(event);\n\t}\n\n\t@Override\n\tpublic void sendTrackballEventSync(MotionEvent event) {\n\t\tbase.sendTrackballEventSync(event);\n\t}\n\n\t@Override\n\tpublic Application newApplication(ClassLoader cl, String className, Context context)\n\t\t\tthrows InstantiationException, IllegalAccessException, ClassNotFoundException {\n\t\treturn base.newApplication(cl, className, context);\n\t}\n\n\t@Override\n\tpublic void callApplicationOnCreate(Application app) {\n\t\tbase.callApplicationOnCreate(app);\n\t}\n\n\t@Override\n\tpublic Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent,\n\t\t\tActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance)\n\t\t\tthrows InstantiationException, IllegalAccessException {\n\t\treturn base.newActivity(clazz, context, token, application, intent, info, title, parent, id,\n\t\t\t\tlastNonConfigurationInstance);\n\t}\n\n\t@Override\n\tpublic Activity newActivity(ClassLoader cl, String className, Intent intent)\n\t\t\tthrows InstantiationException, IllegalAccessException, ClassNotFoundException {\n\t\treturn base.newActivity(cl, className, intent);\n\t}\n\n\t@Override\n\tpublic void callActivityOnCreate(Activity activity, Bundle icicle) {\n\t\tbase.callActivityOnCreate(activity, icicle);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\t@Override\n\tpublic void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {\n\t\tbase.callActivityOnCreate(activity, icicle, persistentState);\n\t}\n\n\t@Override\n\tpublic void callActivityOnDestroy(Activity activity) {\n\t\tbase.callActivityOnDestroy(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {\n\t\tbase.callActivityOnRestoreInstanceState(activity, savedInstanceState);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\t@Override\n\tpublic void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,\n\t\t\tPersistableBundle persistentState) {\n\t\tbase.callActivityOnRestoreInstanceState(activity, savedInstanceState, persistentState);\n\t}\n\n\t@Override\n\tpublic void callActivityOnPostCreate(Activity activity, Bundle icicle) {\n\t\tbase.callActivityOnPostCreate(activity, icicle);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\t@Override\n\tpublic void callActivityOnPostCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {\n\t\tbase.callActivityOnPostCreate(activity, icicle, persistentState);\n\t}\n\n\t@Override\n\tpublic void callActivityOnNewIntent(Activity activity, Intent intent) {\n\t\tbase.callActivityOnNewIntent(activity, intent);\n\t}\n\n\n\t@Override\n\tpublic void callActivityOnStart(Activity activity) {\n\t\tbase.callActivityOnStart(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnRestart(Activity activity) {\n\t\tbase.callActivityOnRestart(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnResume(Activity activity) {\n\t\tbase.callActivityOnResume(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnStop(Activity activity) {\n\t\tbase.callActivityOnStop(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {\n\t\tbase.callActivityOnSaveInstanceState(activity, outState);\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\t@Override\n\tpublic void callActivityOnSaveInstanceState(Activity activity, Bundle outState,\n\t\t\tPersistableBundle outPersistentState) {\n\t\tbase.callActivityOnSaveInstanceState(activity, outState, outPersistentState);\n\t}\n\n\t@Override\n\tpublic void callActivityOnPause(Activity activity) {\n\t\tbase.callActivityOnPause(activity);\n\t}\n\n\t@Override\n\tpublic void callActivityOnUserLeaving(Activity activity) {\n\t\tbase.callActivityOnUserLeaving(activity);\n\t}\n\n\t@Override\n\tpublic Bundle getAllocCounts() {\n\t\treturn base.getAllocCounts();\n\t}\n\n\t@Override\n\tpublic Bundle getBinderCounts() {\n\t\treturn base.getBinderCounts();\n\t}\n\n\n\t@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)\n\t@Override\n\tpublic UiAutomation getUiAutomation() {\n\t\treturn base.getUiAutomation();\n\t}\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/delegate/PhoneInfoDelegate.java",
    "content": "package com.lody.virtual.client.hook.delegate;\r\n\r\npublic interface PhoneInfoDelegate {\r\n\r\n    /***\r\n     * Fake the Device ID.\r\n     *\r\n     * @param oldDeviceId old DeviceId\r\n     * @param userId      user\r\n     */\r\n    String getDeviceId(String oldDeviceId, int userId);\r\n\r\n    /***\r\n     * Fake the BluetoothAddress\r\n     *\r\n     * @param oldBluetoothAddress old BluetoothAddress\r\n     * @param userId              user\r\n     */\r\n    String getBluetoothAddress(String oldBluetoothAddress, int userId);\r\n\r\n    /***\r\n     * Fake the macAddress\r\n     *\r\n     * @param oldMacAddress old MacAddress\r\n     * @param userId        user\r\n     */\r\n    String getMacAddress(String oldMacAddress, int userId);\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/delegate/TaskDescriptionDelegate.java",
    "content": "package com.lody.virtual.client.hook.delegate;\r\n\r\nimport android.annotation.TargetApi;\r\nimport android.app.Activity;\r\nimport android.app.ActivityManager;\r\nimport android.os.Build;\r\n\r\npublic interface TaskDescriptionDelegate {\r\n    public ActivityManager.TaskDescription getTaskDescription(ActivityManager.TaskDescription oldTaskDescription);\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/DownloadProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport android.app.DownloadManager;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.MethodBox;\n\nimport java.lang.reflect.InvocationTargetException;\n\n/**\n * @author Lody\n */\n\nclass DownloadProviderHook extends ExternalProviderHook {\n\n    private static final String TAG = DownloadProviderHook.class.getSimpleName();\n\n    private static final String COLUMN_NOTIFICATION_PACKAGE = \"notificationpackage\";\n    private static final String COLUMN_IS_PUBLIC_API = \"is_public_api\";\n    private static final String COLUMN_OTHER_UID = \"otheruid\";\n    private static final String COLUMN_COOKIE_DATA = \"cookiedata\";\n    private static final String COLUMN_NOTIFICATION_CLASS = \"notificationclass\";\n    private static final String INSERT_KEY_PREFIX = \"http_header_\";\n\n    private static final String[] ENFORCE_REMOVE_COLUMNS = {\n            COLUMN_OTHER_UID,\n            COLUMN_NOTIFICATION_CLASS\n    };\n\n    DownloadProviderHook(Object base) {\n        super(base);\n    }\n\n    @Override\n    public Uri insert(MethodBox methodBox, Uri url, ContentValues initialValues) throws InvocationTargetException {\n        if (initialValues.containsKey(COLUMN_NOTIFICATION_PACKAGE)) {\n            initialValues.put(COLUMN_NOTIFICATION_PACKAGE, VirtualCore.get().getHostPkg());\n        }\n        if (initialValues.containsKey(COLUMN_COOKIE_DATA)) {\n            String cookie = initialValues.getAsString(COLUMN_COOKIE_DATA);\n            initialValues.remove(COLUMN_COOKIE_DATA);\n            // retrieve the next free INSERT_KEY_PREFIX\n            int headerIndex = 0;\n            while (initialValues.containsKey(INSERT_KEY_PREFIX + headerIndex)) {\n                headerIndex++;\n            }\n            // add the cookie\n            initialValues.put(INSERT_KEY_PREFIX + headerIndex, \"Cookie\" + \": \" + cookie);\n        }\n        if (!initialValues.containsKey(COLUMN_IS_PUBLIC_API)) {\n            initialValues.put(COLUMN_IS_PUBLIC_API, true);\n        }\n        for (String column : ENFORCE_REMOVE_COLUMNS) {\n            if (initialValues.containsKey(column)) {\n                initialValues.remove(column);\n            }\n        }\n        return super.insert(methodBox, url, initialValues);\n    }\n\n    @Override\n    public Cursor query(MethodBox methodBox, Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, Bundle originQueryArgs) throws InvocationTargetException {\n        Cursor cursor = super.query(methodBox, url, projection, selection, selectionArgs, sortOrder, originQueryArgs);\n        return new QueryRedirectCursor(cursor, DownloadManager.COLUMN_LOCAL_FILENAME);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/ExternalProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\npublic class ExternalProviderHook extends ProviderHook {\n\n    public ExternalProviderHook(Object base) {\n        super(base);\n    }\n\n    @Override\n    protected void processArgs(Method method, Object... args) {\n        if (args != null && args.length > 0 && args[0] instanceof String) {\n            String pkg = (String) args[0];\n            if (VirtualCore.get().isAppInstalled(pkg)) {\n                args[0] = VirtualCore.get().getHostPkg();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/InternalProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\n/**\n * @author Lody\n */\n\npublic class InternalProviderHook extends ProviderHook {\n\n    public InternalProviderHook(Object base) {\n        super(base);\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/MediaProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.MediaStore;\n\nimport com.lody.virtual.client.NativeEngine;\nimport com.lody.virtual.client.hook.base.MethodBox;\n\nimport java.lang.reflect.InvocationTargetException;\n\n/**\n * @author weishu\n * @date 2018/6/28.\n */\nclass MediaProviderHook extends ProviderHook {\n    private static final String COLUMN_NAME = \"_data\";\n\n    MediaProviderHook(Object base) {\n        super(base);\n    }\n\n    @Override\n    public Uri insert(MethodBox methodBox, Uri url, ContentValues initialValues) throws InvocationTargetException {\n        if (!(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.equals(url) ||\n                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.equals(url)) ||\n                MediaStore.Video.Media.INTERNAL_CONTENT_URI.equals(url) ||\n                MediaStore.Video.Media.EXTERNAL_CONTENT_URI.equals(url) ||\n                MediaStore.Images.Media.INTERNAL_CONTENT_URI.equals(url) ||\n                MediaStore.Images.Media.EXTERNAL_CONTENT_URI.equals(url)\n                ) {\n            return super.insert(methodBox, url, initialValues);\n        }\n\n        Object v2 = initialValues.get(COLUMN_NAME);\n        if (!(v2 instanceof String)) {\n            return super.insert(methodBox, url, initialValues);\n        }\n        String path = NativeEngine.getEscapePath((String) v2);\n        initialValues.put(COLUMN_NAME, path);\n        return super.insert(methodBox, url, initialValues);\n    }\n\n    @Override\n    public Cursor query(MethodBox methodBox, Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, Bundle originQueryArgs) throws InvocationTargetException {\n        Cursor cursor = super.query(methodBox, url, projection, selection, selectionArgs, sortOrder, originQueryArgs);\n        return new QueryRedirectCursor(cursor, COLUMN_NAME);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/ProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport android.content.ContentValues;\nimport android.content.res.AssetFileDescriptor;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IInterface;\nimport android.os.ParcelFileDescriptor;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.fixer.ContextFixer;\nimport com.lody.virtual.client.hook.base.MethodBox;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport mirror.android.content.IContentProvider;\n\n/**\n * @author Lody\n */\n\npublic class ProviderHook implements InvocationHandler {\n\n    public static final String QUERY_ARG_SQL_SELECTION = \"android:query-arg-sql-selection\";\n\n    public static final String QUERY_ARG_SQL_SELECTION_ARGS =\n            \"android:query-arg-sql-selection-args\";\n    public static final String QUERY_ARG_SQL_SORT_ORDER = \"android:query-arg-sql-sort-order\";\n\n\n    private static final Map<String, HookFetcher> PROVIDER_MAP = new HashMap<>();\n\n    static {\n        PROVIDER_MAP.put(\"settings\", new HookFetcher() {\n            @Override\n            public ProviderHook fetch(boolean external, IInterface provider) {\n                return new SettingsProviderHook(provider);\n            }\n        });\n        PROVIDER_MAP.put(\"downloads\", new HookFetcher() {\n            @Override\n            public ProviderHook fetch(boolean external, IInterface provider) {\n                return new DownloadProviderHook(provider);\n            }\n        });\n        PROVIDER_MAP.put(\"media\", new HookFetcher() {\n            @Override\n            public ProviderHook fetch(boolean external, IInterface provider) {\n                return new MediaProviderHook(provider);\n            }\n        });\n    }\n\n    protected final Object mBase;\n\n    public ProviderHook(Object base) {\n        this.mBase = base;\n    }\n\n    private static HookFetcher fetchHook(String authority) {\n        HookFetcher fetcher = PROVIDER_MAP.get(authority);\n        if (fetcher == null) {\n            fetcher = new HookFetcher() {\n                @Override\n                public ProviderHook fetch(boolean external, IInterface provider) {\n                    if (external) {\n                        return new ExternalProviderHook(provider);\n                    }\n                    return new InternalProviderHook(provider);\n                }\n            };\n        }\n        return fetcher;\n    }\n\n    private static IInterface createProxy(IInterface provider, ProviderHook hook) {\n        if (provider == null || hook == null) {\n            return null;\n        }\n        return (IInterface) Proxy.newProxyInstance(provider.getClass().getClassLoader(), new Class[]{\n                IContentProvider.TYPE,\n        }, hook);\n    }\n\n    public static IInterface createProxy(boolean external, String authority, IInterface provider) {\n        if (provider instanceof Proxy && Proxy.getInvocationHandler(provider) instanceof ProviderHook) {\n            return provider;\n        }\n        ProviderHook.HookFetcher fetcher = ProviderHook.fetchHook(authority);\n        if (fetcher != null) {\n            ProviderHook hook = fetcher.fetch(external, provider);\n            IInterface proxyProvider = ProviderHook.createProxy(provider, hook);\n            if (proxyProvider != null) {\n                provider = proxyProvider;\n            }\n        }\n        return provider;\n    }\n\n    public Bundle call(MethodBox methodBox, String method, String arg, Bundle extras) throws InvocationTargetException {\n        return methodBox.call();\n    }\n\n    public Uri insert(MethodBox methodBox, Uri url, ContentValues initialValues) throws InvocationTargetException {\n\n        return (Uri) methodBox.call();\n    }\n\n    public Cursor query(MethodBox methodBox, Uri url, String[] projection, String selection,\n                        String[] selectionArgs, String sortOrder, Bundle originQueryArgs) throws InvocationTargetException {\n        return (Cursor) methodBox.call();\n    }\n\n    public String getType(MethodBox methodBox, Uri url) throws InvocationTargetException {\n        return (String) methodBox.call();\n    }\n\n    public int bulkInsert(MethodBox methodBox, Uri url, ContentValues[] initialValues) throws InvocationTargetException {\n        return (int) methodBox.call();\n    }\n\n    public int delete(MethodBox methodBox, Uri url, String selection, String[] selectionArgs) throws InvocationTargetException {\n        return (int) methodBox.call();\n    }\n\n    public int update(MethodBox methodBox, Uri url, ContentValues values, String selection,\n                      String[] selectionArgs) throws InvocationTargetException {\n        return (int) methodBox.call();\n    }\n\n    public ParcelFileDescriptor openFile(MethodBox methodBox, Uri url, String mode) throws InvocationTargetException {\n        return (ParcelFileDescriptor) methodBox.call();\n    }\n\n    public AssetFileDescriptor openAssetFile(MethodBox methodBox, Uri url, String mode) throws InvocationTargetException {\n        return (AssetFileDescriptor) methodBox.call();\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object... args) throws Throwable {\n        try {\n            processArgs(method, args);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        MethodBox methodBox = new MethodBox(method, mBase, args);\n        int start = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 ? 1 : 0;\n        if (BuildCompat.isS()) {\n            // https://cs.android.com/android/platform/superproject/+/android-12.0.0_r16:frameworks/base/core/java/android/content/IContentProvider.java\n            start = 1;\n        } else if (BuildCompat.isR()) {\n            // Android 11: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/content/IContentProvider.java?q=IContentProvider&ss=android%2Fplatform%2Fsuperproject\n            start = 2;\n        }\n        if (BuildCompat.isS() ) {\n            tryFixAttributionSource(args);\n        }\n        try {\n            String name = method.getName();\n            if (\"call\".equals(name)) {\n                if (BuildCompat.isS()) {\n                    // What's the fuck with Google???\n                    // https://cs.android.com/android/platform/superproject/+/android-12.0.0_r1:frameworks/base/core/java/android/content/IContentProvider.java;l=123\n                    start = 2;\n                } else if (BuildCompat.isR()) {\n                    start = 3;\n                } else if (BuildCompat.isQ()) {\n                    start = 2;\n                }\n                String methodName = (String) args[start];\n                String arg = (String) args[start + 1];\n                Bundle extras = (Bundle) args[start + 2];\n                return call(methodBox, methodName, arg, extras);\n            } else if (\"insert\".equals(name)) {\n                Uri url = (Uri) args[start];\n                ContentValues initialValues = (ContentValues) args[start + 1];\n                return insert(methodBox, url, initialValues);\n            } else if (\"getType\".equals(name)) {\n                return getType(methodBox, (Uri) args[0]);\n            } else if (\"delete\".equals(name)) {\n                Uri url = (Uri) args[start];\n                String selection = (String) args[start + 1];\n                String[] selectionArgs = (String[]) args[start + 2];\n                return delete(methodBox, url, selection, selectionArgs);\n            } else if (\"bulkInsert\".equals(name)) {\n                Uri url = (Uri) args[start];\n                ContentValues[] initialValues = (ContentValues[]) args[start + 1];\n                return bulkInsert(methodBox, url, initialValues);\n            } else if (\"update\".equals(name)) {\n                Uri url = (Uri) args[start];\n                ContentValues values = (ContentValues) args[start + 1];\n                String selection = (String) args[start + 2];\n                String[] selectionArgs = (String[]) args[start + 3];\n                return update(methodBox, url, values, selection, selectionArgs);\n            } else if (\"openFile\".equals(name)) {\n                Uri url = (Uri) args[start];\n                String mode = (String) args[start + 1];\n                return openFile(methodBox, url, mode);\n            } else if (\"openAssetFile\".equals(name)) {\n                Uri url = (Uri) args[start];\n                String mode = (String) args[start + 1];\n                return openAssetFile(methodBox, url, mode);\n            } else if (\"query\".equals(name)) {\n                Uri url = (Uri) args[start];\n                String[] projection = (String[]) args[start + 1];\n                String selection = null;\n                String[] selectionArgs = null;\n                String sortOrder = null;\n                Bundle queryArgs = null;\n\n                if (Build.VERSION.SDK_INT >= 26) {\n                    queryArgs = (Bundle) args[start + 2];\n                    if (queryArgs != null) {\n                        selection = queryArgs.getString(QUERY_ARG_SQL_SELECTION);\n                        selectionArgs = queryArgs.getStringArray(QUERY_ARG_SQL_SELECTION_ARGS);\n                        sortOrder = queryArgs.getString(QUERY_ARG_SQL_SORT_ORDER);\n                    }\n                } else {\n                    selection = (String) args[start + 2];\n                    selectionArgs = (String[]) args[start + 3];\n                    sortOrder = (String) args[start + 4];\n                }\n                return query(methodBox, url, projection, selection, selectionArgs, sortOrder, queryArgs);\n            }\n            return methodBox.call();\n        } catch (Throwable e) {\n            VLog.d(\"ProviderHook\", \"call: %s (%s) with error\", method.getName(), Arrays.toString(args));\n            if (e instanceof InvocationTargetException) {\n                throw e.getCause();\n            }\n            throw e;\n        }\n    }\n\n    protected void processArgs(Method method, Object... args) {\n\n    }\n\n    public interface HookFetcher {\n        ProviderHook fetch(boolean external, IInterface provider);\n    }\n\n    private void tryFixAttributionSource(Object[] args) {\n        if (args == null || args.length == 0) {\n            return;\n        }\n        Object attribution = args[0];\n        if (attribution == null) {\n            return;\n        }\n        if (!attribution.getClass().getName().equals(\"android.content.AttributionSource\")) {\n            return;\n        }\n\n        ContextFixer.fixAttributionSource(attribution, VirtualCore.get().getHostPkg(), VirtualCore.get().myUid());\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/QueryRedirectCursor.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport android.database.CharArrayBuffer;\nimport android.database.CrossProcessCursorWrapper;\nimport android.database.Cursor;\n\nimport com.lody.virtual.client.NativeEngine;\n\n/**\n * @author weishu\n * @date 2018/6/29.\n */\nclass QueryRedirectCursor extends CrossProcessCursorWrapper {\n\n    private int dataIndex;\n\n    /**\n     * Creates a cross process cursor wrapper.\n     *\n     * @param cursor The underlying cursor to wrap.\n     */\n    QueryRedirectCursor(Cursor cursor, String columnName) {\n        super(cursor);\n        dataIndex = cursor.getColumnIndex(columnName);\n    }\n\n    @Override\n    public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {\n        if (columnIndex < 0 || columnIndex != this.dataIndex || buffer == null) {\n            super.copyStringToBuffer(columnIndex, buffer);\n            return;\n        }\n\n        String path = getString(columnIndex);\n        if (path == null) {\n            super.copyStringToBuffer(columnIndex, buffer);\n            return;\n        }\n\n        char[] chars = path.toCharArray();\n        int v1 = Math.min(chars.length, buffer.data.length);\n        System.arraycopy(chars, 0, buffer.data, 0, v1);\n        buffer.sizeCopied = v1;\n    }\n\n    @Override\n    public String getString(int columnIndex) {\n        String originalPath = super.getString(columnIndex);\n        if (columnIndex < 0 || columnIndex != this.dataIndex) {\n            return originalPath;\n        }\n        return NativeEngine.getEscapePath(originalPath);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/providers/SettingsProviderHook.java",
    "content": "package com.lody.virtual.client.hook.providers;\n\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.hook.base.MethodBox;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class SettingsProviderHook extends ExternalProviderHook {\n\n    private static final String TAG = SettingsProviderHook.class.getSimpleName();\n\n    private static final int METHOD_GET = 0;\n    private static final int METHOD_PUT = 1;\n\n    private static final Map<String, String> PRE_SET_VALUES = new HashMap<>();\n\n    static {\n        PRE_SET_VALUES.put(\"user_setup_complete\", \"1\");\n        PRE_SET_VALUES.put(\"install_non_market_apps\", \"0\");\n    }\n\n\n    public SettingsProviderHook(Object base) {\n        super(base);\n    }\n\n    private static int getMethodType(String method) {\n        if (method.startsWith(\"GET_\")) {\n            return METHOD_GET;\n        }\n        if (method.startsWith(\"PUT_\")) {\n            return METHOD_PUT;\n        }\n        return -1;\n    }\n\n    private static boolean isSecureMethod(String method) {\n        return method.endsWith(\"secure\");\n    }\n\n\n    @Override\n    public Bundle call(MethodBox methodBox, String method, String arg, Bundle extras) throws InvocationTargetException {\n        if (!VClientImpl.get().isBound()) {\n            return methodBox.call();\n        }\n        int methodType = getMethodType(method);\n        if (METHOD_GET == methodType) {\n            String presetValue = PRE_SET_VALUES.get(arg);\n            if (presetValue != null) {\n                return wrapBundle(arg, presetValue);\n            }\n            if (\"android_id\".equals(arg)) {\n                return wrapBundle(\"android_id\", VClientImpl.get().getDeviceInfo().androidId);\n            }\n        }\n        if (METHOD_PUT == methodType) {\n            if (isSecureMethod(method)) {\n                return null;\n            }\n        }\n        try {\n            return methodBox.call();\n        } catch (InvocationTargetException e) {\n            if (e.getCause() instanceof SecurityException) {\n                return null;\n            }\n            throw e;\n        }\n    }\n\n    private Bundle wrapBundle(String name, String value) {\n        Bundle bundle = new Bundle();\n        if (Build.VERSION.SDK_INT >= 24) {\n            bundle.putString(\"name\", name);\n            bundle.putString(\"value\", value);\n        } else {\n            bundle.putString(name, value);\n        }\n        return bundle;\n    }\n\n    @Override\n    protected void processArgs(Method method, Object... args) {\n        super.processArgs(method, args);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/account/AccountManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.account;\n\nimport android.accounts.Account;\nimport android.accounts.IAccountManagerResponse;\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.ipc.VAccountManager;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.accounts.IAccountManager;\n\n/**\n * @author Lody\n */\npublic class AccountManagerStub extends BinderInvocationProxy {\n\n\tprivate static VAccountManager Mgr = VAccountManager.get();\n\n\tpublic AccountManagerStub() {\n\t\tsuper(IAccountManager.Stub.asInterface, Context.ACCOUNT_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new getPassword());\n\t\taddMethodProxy(new getUserData());\n\t\taddMethodProxy(new getAuthenticatorTypes());\n\t\taddMethodProxy(new getAccounts());\n\t\taddMethodProxy(new getAccountsForPackage());\n\t\taddMethodProxy(new getAccountsByTypeForPackage());\n\t\taddMethodProxy(new getAccountsAsUser());\n\t\taddMethodProxy(new hasFeatures());\n\t\taddMethodProxy(new getAccountsByFeatures());\n\t\taddMethodProxy(new addAccountExplicitly());\n\t\taddMethodProxy(new removeAccount());\n\t\taddMethodProxy(new removeAccountAsUser());\n\t\taddMethodProxy(new removeAccountExplicitly());\n\t\taddMethodProxy(new copyAccountToUser());\n\t\taddMethodProxy(new invalidateAuthToken());\n\t\taddMethodProxy(new peekAuthToken());\n\t\taddMethodProxy(new setAuthToken());\n\t\taddMethodProxy(new setPassword());\n\t\taddMethodProxy(new clearPassword());\n\t\taddMethodProxy(new setUserData());\n\t\taddMethodProxy(new updateAppPermission());\n\t\taddMethodProxy(new getAuthToken());\n\t\taddMethodProxy(new addAccount());\n\t\taddMethodProxy(new addAccountAsUser());\n\t\taddMethodProxy(new updateCredentials());\n\t\taddMethodProxy(new editProperties());\n\t\taddMethodProxy(new confirmCredentialsAsUser());\n\t\taddMethodProxy(new accountAuthenticated());\n\t\taddMethodProxy(new getAuthTokenLabel());\n\t\taddMethodProxy(new addSharedAccountAsUser());\n\t\taddMethodProxy(new getSharedAccountsAsUser());\n\t\taddMethodProxy(new removeSharedAccountAsUser());\n\t\taddMethodProxy(new renameAccount());\n\t\taddMethodProxy(new getPreviousName());\n\t\taddMethodProxy(new renameSharedAccountAsUser());\n\n\t\taddMethodProxy(new setAccountVisibility());\n\t}\n\n\tprivate static class getPassword extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getPassword\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\treturn Mgr.getPassword(account);\n\t\t}\n\t}\n\n\tprivate static class getUserData extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getUserData\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString key = (String) args[1];\n\t\t\treturn Mgr.getUserData(account, key);\n\t\t}\n\t}\n\n\tprivate static class getAuthenticatorTypes extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAuthenticatorTypes\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn Mgr.getAuthenticatorTypes();\n\t\t}\n\t}\n\n\tprivate static class getAccounts extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAccounts\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tString accountType = (String) args[0];\n\t\t\treturn Mgr.getAccounts(accountType);\n\t\t}\n\t}\n\n\tprivate static class getAccountsForPackage extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAccountsForPackage\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tString packageName = (String) args[0];\n\t\t\treturn Mgr.getAccounts(null);\n\t\t}\n\t}\n\n\tprivate static class getAccountsByTypeForPackage extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAccountsByTypeForPackage\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tString type = (String) args[0];\n\t\t\tString packageName = (String) args[1];\n\t\t\treturn Mgr.getAccounts(type);\n\t\t}\n\t}\n\n\tprivate static class getAccountsAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAccountsAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tString accountType = (String) args[0];\n\t\t\treturn Mgr.getAccounts(accountType);\n\t\t}\n\t}\n\n\tprivate static class hasFeatures extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"hasFeatures\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tString[] features = (String[]) args[2];\n\t\t\tMgr.hasFeatures(response, account, features);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class getAccountsByFeatures extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAccountsByFeatures\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tString accountType = (String) args[1];\n\t\t\tString[] features = (String[]) args[2];\n\t\t\tMgr.getAccountsByFeatures(response, accountType, features);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class addAccountExplicitly extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"addAccountExplicitly\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString password = (String) args[1];\n\t\t\tBundle extras = (Bundle) args[2];\n\t\t\treturn Mgr.addAccountExplicitly(account, password, extras);\n\t\t}\n\t}\n\n\tprivate static class removeAccount extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"removeAccount\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tboolean expectActivityLaunch = (boolean) args[2];\n\t\t\tMgr.removeAccount(response, account, expectActivityLaunch);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class removeAccountAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"removeAccountAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tboolean expectActivityLaunch = (boolean) args[2];\n\t\t\tMgr.removeAccount(response, account, expectActivityLaunch);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class removeAccountExplicitly extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"removeAccountExplicitly\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\treturn Mgr.removeAccountExplicitly(account);\n\t\t}\n\t}\n\n\tprivate static class copyAccountToUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"copyAccountToUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tint userFrom = (int) args[2];\n\t\t\tint userTo = (int) args[3];\n\t\t\tmethod.invoke(who, args);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class invalidateAuthToken extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"invalidateAuthToken\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tString accountType = (String) args[0];\n\t\t\tString authToken = (String) args[1];\n\t\t\tMgr.invalidateAuthToken(accountType, authToken);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class peekAuthToken extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"peekAuthToken\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString authTokenType = (String) args[1];\n\t\t\treturn Mgr.peekAuthToken(account, authTokenType);\n\t\t}\n\t}\n\n\tprivate static class setAuthToken extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setAuthToken\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString authTokenType = (String) args[1];\n\t\t\tString authToken = (String) args[2];\n\t\t\tMgr.setAuthToken(account, authTokenType, authToken);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class setPassword extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setPassword\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString password = (String) args[1];\n\t\t\tMgr.setPassword(account, password);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class clearPassword extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"clearPassword\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tMgr.clearPassword(account);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class setUserData extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setUserData\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString key = (String) args[1];\n\t\t\tString value = (String) args[2];\n\t\t\tMgr.setUserData(account, key, value);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class updateAppPermission extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"updateAppPermission\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tString authTokenType = (String) args[1];\n\t\t\tint uid = (int) args[2];\n\t\t\tboolean val = (boolean) args[3];\n\t\t\tmethod.invoke(who, args);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class getAuthToken extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAuthToken\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tString authTokenType = (String) args[2];\n\t\t\tboolean notifyOnAuthFailure = (boolean) args[3];\n\t\t\tboolean expectActivityLaunch = (boolean) args[4];\n\t\t\tBundle options = (Bundle) args[5];\n\t\t\tMgr.getAuthToken(response, account, authTokenType, notifyOnAuthFailure, expectActivityLaunch, options);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class addAccount extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"addAccount\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tString accountType = (String) args[1];\n\t\t\tString authTokenType = (String) args[2];\n\t\t\tString[] requiredFeatures = (String[]) args[3];\n\t\t\tboolean expectActivityLaunch = (boolean) args[4];\n\t\t\tBundle options = (Bundle) args[5];\n\t\t\tMgr.addAccount(response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, options);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class addAccountAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"addAccountAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tString accountType = (String) args[1];\n\t\t\tString authTokenType = (String) args[2];\n\t\t\tString[] requiredFeatures = (String[]) args[3];\n\t\t\tboolean expectActivityLaunch = (boolean) args[4];\n\t\t\tBundle options = (Bundle) args[5];\n\t\t\tMgr.addAccount(response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, options);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class updateCredentials extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"updateCredentials\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tString authTokenType = (String) args[2];\n\t\t\tboolean expectActivityLaunch = (boolean) args[3];\n\t\t\tBundle options = (Bundle) args[4];\n\t\t\tMgr.updateCredentials(response, account, authTokenType, expectActivityLaunch, options);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class editProperties extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"editProperties\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tString authTokenType = (String) args[1];\n\t\t\tboolean expectActivityLaunch = (boolean) args[2];\n\t\t\tMgr.editProperties(response, authTokenType, expectActivityLaunch);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class confirmCredentialsAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"confirmCredentialsAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount account = (Account) args[1];\n\t\t\tBundle options = (Bundle) args[2];\n\t\t\tboolean expectActivityLaunch = (boolean) args[3];\n\t\t\tMgr.confirmCredentials(response, account, options, expectActivityLaunch);\n\t\t\treturn 0;\n\n\t\t}\n\t}\n\n\tprivate static class accountAuthenticated extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"accountAuthenticated\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\treturn Mgr.accountAuthenticated(account);\n\t\t}\n\t}\n\n\tprivate static class getAuthTokenLabel extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAuthTokenLabel\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tString accountType = (String) args[1];\n\t\t\tString authTokenType = (String) args[2];\n\t\t\tMgr.getAuthTokenLabel(response, accountType, authTokenType);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class addSharedAccountAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"addSharedAccountAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tint userId = (int) args[1];\n\t\t\treturn method.invoke(who, args);\n\t\t}\n\t}\n\n\tprivate static class getSharedAccountsAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getSharedAccountsAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tint userId = (int) args[0];\n\t\t\treturn method.invoke(who, args);\n\t\t}\n\t}\n\n\tprivate static class removeSharedAccountAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"removeSharedAccountAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\tint userId = (int) args[1];\n\t\t\treturn method.invoke(who, args);\n\t\t}\n\t}\n\n\tprivate static class renameAccount extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"renameAccount\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tIAccountManagerResponse response = (IAccountManagerResponse) args[0];\n\t\t\tAccount accountToRename = (Account) args[1];\n\t\t\tString newName = (String) args[2];\n\t\t\tMgr.renameAccount(response, accountToRename, newName);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static class getPreviousName extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getPreviousName\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount account = (Account) args[0];\n\t\t\treturn Mgr.getPreviousName(account);\n\t\t}\n\t}\n\n\tprivate static class renameSharedAccountAsUser extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"renameSharedAccountAsUser\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tAccount accountToRename = (Account) args[0];\n\t\t\tString newName = (String) args[1];\n\t\t\tint userId = (int) args[2];\n\t\t\treturn method.invoke(who, args);\n\t\t}\n\t}\n\n\tprivate static class setAccountVisibility extends MethodProxy {\n\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setAccountVisibility\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn true;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/alarm/AlarmManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.alarm;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.WorkSource;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.IAlarmManager;\n\n/**\n * @author Lody\n *\n * @see android.app.AlarmManager\n */\npublic class AlarmManagerStub extends BinderInvocationProxy {\n\n\tpublic AlarmManagerStub() {\n\t\tsuper(IAlarmManager.Stub.asInterface, Context.ALARM_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new Set());\n\t\taddMethodProxy(new SetTime());\n\t\taddMethodProxy(new SetTimeZone());\n\t}\n\n\tprivate static class SetTimeZone extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setTimeZone\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static class SetTime extends MethodProxy {\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"setTime\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static class Set extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"set\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n\t\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && args[0] instanceof String) {\n\t\t\t\targs[0] = getHostPkg();\n\t\t\t}\n            int index = ArrayUtils.indexOfFirst(args, WorkSource.class);\n            if (index >= 0) {\n                args[index] = null;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.am;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationStub;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastUidMethodProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.compat.ParceledListSliceCompat;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.remote.AppTaskInfo;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport mirror.android.app.ActivityManagerNative;\nimport mirror.android.app.ActivityManagerOreo;\nimport mirror.android.app.IActivityManager;\nimport mirror.android.content.pm.ParceledListSlice;\nimport mirror.android.os.ServiceManager;\nimport mirror.android.util.Singleton;\n\n/**\n * @author Lody\n * @see IActivityManager\n * @see android.app.ActivityManager\n */\n\n@Inject(MethodProxies.class)\npublic class ActivityManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {\n\n    public ActivityManagerStub() {\n        super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        if (BuildCompat.isOreo()) {\n            //Android Oreo(8.X)\n            Object singleton = ActivityManagerOreo.IActivityManagerSingleton.get();\n            Singleton.mInstance.set(singleton, getInvocationStub().getProxyInterface());\n        } else {\n            if (ActivityManagerNative.gDefault.type() == IActivityManager.TYPE) {\n                ActivityManagerNative.gDefault.set(getInvocationStub().getProxyInterface());\n            } else if (ActivityManagerNative.gDefault.type() == Singleton.TYPE) {\n                Object gDefault = ActivityManagerNative.gDefault.get();\n                Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());\n            }\n        }\n        BinderInvocationStub hookAMBinder = new BinderInvocationStub(getInvocationStub().getBaseInterface());\n        hookAMBinder.copyMethodProxies(getInvocationStub());\n        ServiceManager.sCache.get().put(Context.ACTIVITY_SERVICE, hookAMBinder);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        if (VirtualCore.get().isVAppProcess()) {\n            addMethodProxy(new StaticMethodProxy(\"navigateUpTo\") {\n                @Override\n                public Object call(Object who, Method method, Object... args) throws Throwable {\n                    // throw new RuntimeException(\"Call navigateUpTo!!!!\");\n                    VLog.e(\"VA\", \"Call navigateUpTo!!!!\");\n                    return method.invoke(who, args);\n                }\n            });\n            addMethodProxy(new ReplaceLastUidMethodProxy(\"checkPermissionWithToken\"));\n            addMethodProxy(new isUserRunning());\n            addMethodProxy(new ResultStaticMethodProxy(\"updateConfiguration\", 0));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"setAppLockedVerifying\"));\n            addMethodProxy(new StaticMethodProxy(\"checkUriPermission\") {\n                @Override\n                public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n                    return PackageManager.PERMISSION_GRANTED;\n                }\n            });\n            addMethodProxy(new StaticMethodProxy(\"getRecentTasks\") {\n                @Override\n                public Object call(Object who, Method method, Object... args) throws Throwable {\n                    Object _infos = method.invoke(who, args);\n                    //noinspection unchecked\n                    List<ActivityManager.RecentTaskInfo> infos =\n                            ParceledListSliceCompat.isReturnParceledListSlice(method)\n                                    ? ParceledListSlice.getList.call(_infos)\n                                    : (List) _infos;\n                    for (ActivityManager.RecentTaskInfo info : infos) {\n                        AppTaskInfo taskInfo = VActivityManager.get().getTaskInfo(info.id);\n                        if (taskInfo == null) {\n                            continue;\n                        }\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                            try {\n                                info.topActivity = taskInfo.topActivity;\n                                info.baseActivity = taskInfo.baseActivity;\n                            } catch (Throwable e) {\n                                // ignore\n                            }\n                        }\n                        try {\n                            info.origActivity = taskInfo.baseActivity;\n                            info.baseIntent = taskInfo.baseIntent;\n                        } catch (Throwable e) {\n                            // ignore\n                        }\n                    }\n                    return _infos;\n                }\n            });\n            addMethodProxy(new StaticMethodProxy(\"getRunningTasks\") {\n                @Override\n                public Object call(Object who, Method method, Object... args) throws Throwable {\n                    Object _infos = method.invoke(who, args);\n                    //noinspection unchecked\n                    List<ActivityManager.RunningTaskInfo> infos =\n                            ParceledListSliceCompat.isReturnParceledListSlice(method)\n                                    ? ParceledListSlice.getList.call(_infos)\n                                    : (List) _infos;\n                    for (ActivityManager.RunningTaskInfo info : infos) {\n                        AppTaskInfo taskInfo = VActivityManager.get().getTaskInfo(info.id);\n                        if (taskInfo == null) {\n                            continue;\n                        }\n                        info.description = \"Virtual\";\n                        info.topActivity = taskInfo.topActivity;\n                        info.baseActivity = taskInfo.baseActivity;\n                    }\n                    return _infos;\n                }\n            });\n        }\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return ActivityManagerNative.getDefault.call() != getInvocationStub().getProxyInterface();\n    }\n\n    private class isUserRunning extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"isUserRunning\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) {\n            int userId = (int) args[0];\n            return userId == 0;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/ActivityTaskManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.am;\n\nimport android.os.IBinder;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.IActivityTaskManager;\n\n/**\n * @author weishu\n * @date 2019-11-05.\n */\n@Inject(MethodProxies.class)\npublic class ActivityTaskManagerStub extends BinderInvocationProxy {\n    public ActivityTaskManagerStub() {\n        super(IActivityTaskManager.Stub.TYPE, \"activity_task\");\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n\n        addMethodProxy(new StaticMethodProxy(\"activityDestroyed\") {\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                IBinder token = (IBinder) args[0];\n                VActivityManager.get().onActivityDestroy(token);\n                return super.call(who, method, args);\n            }\n        });\n        addMethodProxy(new StaticMethodProxy(\"activityResumed\") {\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                IBinder token = (IBinder) args[0];\n                VActivityManager.get().onActivityResumed(token);\n                return super.call(who, method, args);\n            }\n        });\n        addMethodProxy(new StaticMethodProxy(\"finishActivity\") {\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                IBinder token = (IBinder) args[0];\n                VActivityManager.get().finishActivity(token);\n                return super.call(who, method, args);\n            }\n        });\n\n        if (BuildCompat.isQ()) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getAppTasks\"));\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/HCallbackStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.am;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Message;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.interfaces.IInjector;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.remote.StubActivityRecord;\n\nimport mirror.android.app.ActivityManagerNative;\nimport mirror.android.app.ActivityThread;\nimport mirror.android.app.IActivityManager;\n\n/**\n     * @author Lody\n     * @see Handler.Callback\n     */\n    public class HCallbackStub implements Handler.Callback, IInjector {\n\n\n        private static int LAUNCH_ACTIVITY = -1;\n        private static final int CREATE_SERVICE = ActivityThread.H.CREATE_SERVICE.get();\n        private static final int SCHEDULE_CRASH =\n                ActivityThread.H.SCHEDULE_CRASH != null ? ActivityThread.H.SCHEDULE_CRASH.get() : -1;\n\n        private static final String TAG = HCallbackStub.class.getSimpleName();\n        private static final HCallbackStub sCallback = new HCallbackStub();\n\n        private boolean mCalling = false;\n\n\n        private Handler.Callback otherCallback;\n\n        static {\n            if (android.os.Build.VERSION.SDK_INT < 28) {\n                LAUNCH_ACTIVITY = ActivityThread.H.LAUNCH_ACTIVITY.get();\n            }\n        }\n        private HCallbackStub() {\n        }\n\n        public static HCallbackStub getDefault() {\n            return sCallback;\n        }\n\n        private static Handler getH() {\n            return ActivityThread.mH.get(VirtualCore.mainThread());\n        }\n\n        private static Handler.Callback getHCallback() {\n            try {\n                Handler handler = getH();\n                return mirror.android.os.Handler.mCallback.get(handler);\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        public boolean handleMessage(Message msg) {\n            if (!mCalling) {\n                mCalling = true;\n                try {\n                    if (LAUNCH_ACTIVITY == msg.what) {\n                        if (!handleLaunchActivity(msg)) {\n                            return true;\n                        }\n                    } else if (CREATE_SERVICE == msg.what) {\n                        if (!VClientImpl.get().isBound()) {\n                            ServiceInfo info = Reflect.on(msg.obj).get(\"info\");\n                            VClientImpl.get().bindApplication(info.packageName, info.processName);\n                        }\n                    } else if (SCHEDULE_CRASH == msg.what) {\n                        // to avoid the exception send from System.\n                        return true;\n                    }\n                    if (otherCallback != null) {\n                        boolean desired = otherCallback.handleMessage(msg);\n                        mCalling = false;\n                        return desired;\n                    } else {\n                        mCalling = false;\n                    }\n                } finally {\n                    mCalling = false;\n                }\n            }\n            return false;\n        }\n\n        private boolean handleLaunchActivity(Message msg) {\n            Object r = msg.obj;\n            Intent stubIntent = ActivityThread.ActivityClientRecord.intent.get(r);\n            StubActivityRecord saveInstance = new StubActivityRecord(stubIntent);\n            if (saveInstance.intent == null) {\n                return true;\n            }\n            Intent intent = saveInstance.intent;\n            ComponentName caller = saveInstance.caller;\n            IBinder token = ActivityThread.ActivityClientRecord.token.get(r);\n            ActivityInfo info = saveInstance.info;\n            if (VClientImpl.get().getToken() == null) {\n                InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);\n                if(installedAppInfo == null){\n                    return true;\n                }\n                VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId);\n                getH().sendMessageAtFrontOfQueue(Message.obtain(msg));\n                return false;\n            }\n            if (!VClientImpl.get().isBound()) {\n                VClientImpl.get().bindApplicationForActivity(info.packageName, info.processName, intent);\n                getH().sendMessageAtFrontOfQueue(Message.obtain(msg));\n                return false;\n            }\n            int taskId = IActivityManager.getTaskForActivity.call(\n                    ActivityManagerNative.getDefault.call(),\n                    token,\n                    false\n            );\n            VActivityManager.get().onActivityCreate(ComponentUtils.toComponentName(info), caller, token, info, intent, ComponentUtils.getTaskAffinity(info), taskId, info.launchMode, info.flags);\n            ClassLoader appClassLoader = VClientImpl.get().getClassLoader(info.applicationInfo);\n            intent.setExtrasClassLoader(appClassLoader);\n            ActivityThread.ActivityClientRecord.intent.set(r, intent);\n            ActivityThread.ActivityClientRecord.activityInfo.set(r, info);\n            return true;\n        }\n\n        @Override\n        public void inject() throws Throwable {\n            otherCallback = getHCallback();\n            mirror.android.os.Handler.mCallback.set(getH(), this);\n        }\n\n        @Override\n        public boolean isEnvBad() {\n            Handler.Callback callback = getHCallback();\n            boolean envBad = callback != this;\n            if (callback != null && envBad) {\n                VLog.d(TAG, \"HCallback has bad, other callback = \" + callback);\n            }\n            return envBad;\n        }\n\n    }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.am;\n\nimport android.annotation.TargetApi;\nimport android.app.ActivityManager;\nimport android.app.Application;\nimport android.app.IServiceConnection;\nimport android.app.Notification;\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.IIntentReceiver;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.Icon;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.provider.MediaStore;\nimport android.text.TextUtils;\nimport android.util.TypedValue;\n\nimport com.lody.virtual.client.NativeEngine;\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.badger.BadgerManager;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.env.SpecialComponentList;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.hook.delegate.TaskDescriptionDelegate;\nimport com.lody.virtual.client.hook.providers.ProviderHook;\nimport com.lody.virtual.client.hook.secondary.ServiceConnectionDelegate;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport com.lody.virtual.client.ipc.ActivityClientRecord;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.ipc.VNotificationManager;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.client.stub.ChooserActivity;\nimport com.lody.virtual.client.stub.StubPendingActivity;\nimport com.lody.virtual.client.stub.StubPendingReceiver;\nimport com.lody.virtual.client.stub.StubPendingService;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.compat.ActivityManagerCompat;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.BitmapUtils;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.helper.utils.DrawableUtils;\nimport com.lody.virtual.helper.utils.EncodeUtils;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.os.VUserInfo;\nimport com.lody.virtual.remote.AppTaskInfo;\nimport com.lody.virtual.server.interfaces.IAppRequestListener;\n\nimport java.io.File;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.WeakHashMap;\n\nimport mirror.android.app.IActivityManager;\nimport mirror.android.app.LoadedApk;\nimport mirror.android.content.ContentProviderHolderOreo;\nimport mirror.android.content.IIntentReceiverJB;\nimport mirror.android.content.pm.UserInfo;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"unused\")\nclass MethodProxies {\n\n\n    static class ForceStopPackage extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"forceStopPackage\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            int userId = VUserHandle.myUserId();\n            VActivityManager.get().killAppByPkg(pkg, userId);\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class CrashApplication extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"crashApplication\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class AddPackageDependency extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"addPackageDependency\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GetPackageForToken extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageForToken\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            String pkg = VActivityManager.get().getPackageForToken(token);\n            if (pkg != null) {\n                return pkg;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class UnbindService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"unbindService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IServiceConnection conn = (IServiceConnection) args[0];\n            ServiceConnectionDelegate delegate = ServiceConnectionDelegate.removeDelegate(conn);\n            if (delegate == null) {\n                return method.invoke(who, args);\n            }\n            return VActivityManager.get().unbindService(delegate);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess() || isServerProcess();\n        }\n    }\n\n    static class GetContentProviderExternal extends GetContentProvider {\n\n        @Override\n        public String getMethodName() {\n            return \"getContentProviderExternal\";\n        }\n\n        @Override\n        public int getProviderNameIndex() {\n            return 0;\n        }\n\n        @Override\n        public int getPackageIndex() {\n            return -1;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class StartVoiceActivity extends StartActivity {\n        @Override\n        public String getMethodName() {\n            return \"startVoiceActivity\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class UnstableProviderDied extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"unstableProviderDied\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (args[0] == null) {\n                return 0;\n            }\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class PeekService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"peekService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceLastAppPkg(args);\n            Intent service = (Intent) args[0];\n            String resolvedType = (String) args[1];\n            return VActivityManager.get().peekService(service, resolvedType);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPackageAskScreenCompat extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageAskScreenCompat\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (args.length > 0 && args[0] instanceof String) {\n                    args[0] = getHostPkg();\n                }\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetIntentSender extends MethodProxy {\n\n        protected int mIntentIndex = 5;\n        protected int mResolvedTypesIndex = 6;\n        protected int mFlagsIndex = 7;\n\n        @Override\n        public String getMethodName() {\n            return \"getIntentSender\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String creator = (String) args[1];\n            String[] resolvedTypes = (String[]) args[mResolvedTypesIndex];\n            int type = (int) args[0];\n            int flags = (int) args[mFlagsIndex];\n            if (args[5] instanceof Intent[]) {\n                Intent[] intents = (Intent[]) args[mIntentIndex];\n                for (int i = 0; i < intents.length; i++) {\n                    Intent intent = intents[i];\n                    if (resolvedTypes != null && i < resolvedTypes.length) {\n                        intent.setDataAndType(intent.getData(), resolvedTypes[i]);\n                    }\n                    Intent targetIntent = redirectIntentSender(type, creator, intent);\n                    if (targetIntent != null) {\n                        intents[i] = targetIntent;\n                    }\n                }\n            }\n            args[mFlagsIndex] = flags;\n            args[1] = getHostPkg();\n            // Force userId to 0\n            if (args[args.length - 1] instanceof Integer) {\n                args[args.length - 1] = 0;\n            }\n            IInterface sender = (IInterface) method.invoke(who, args);\n            if (sender != null && creator != null) {\n                VActivityManager.get().addPendingIntent(sender.asBinder(), creator);\n            }\n            return sender;\n        }\n\n        private Intent redirectIntentSender(int type, String creator, Intent intent) {\n            Intent newIntent = intent.cloneFilter();\n            switch (type) {\n                case ActivityManagerCompat.INTENT_SENDER_ACTIVITY: {\n                    ComponentInfo info = VirtualCore.get().resolveActivityInfo(intent, VUserHandle.myUserId());\n                    if (info != null) {\n                        newIntent.setClass(getHostContext(), StubPendingActivity.class);\n                        newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    }\n                }\n                break;\n                case ActivityManagerCompat.INTENT_SENDER_SERVICE: {\n                    ComponentInfo info = VirtualCore.get().resolveServiceInfo(intent, VUserHandle.myUserId());\n                    if (info != null) {\n                        newIntent.setClass(getHostContext(), StubPendingService.class);\n                    }\n                }\n                break;\n                case ActivityManagerCompat.INTENT_SENDER_BROADCAST: {\n                    newIntent.setClass(getHostContext(), StubPendingReceiver.class);\n                }\n                break;\n                default:\n                    return null;\n            }\n            newIntent.putExtra(\"_VA_|_user_id_\", VUserHandle.myUserId());\n            newIntent.putExtra(\"_VA_|_intent_\", intent);\n            newIntent.putExtra(\"_VA_|_creator_\", creator);\n            newIntent.putExtra(\"_VA_|_from_inner_\", true);\n            return newIntent;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n\n    static class OverridePendingTransition extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"overridePendingTransition\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            // Many application crash/darkscreen if not return null.\n            return null;\n        }\n    }\n\n    static class StartActivity extends MethodProxy {\n\n        private static final String SCHEME_FILE = \"file\";\n        private static final String SCHEME_PACKAGE = \"package\";\n        private static final String SCHEME_CONTENT = \"content\";\n\n        @Override\n        public String getMethodName() {\n            return \"startActivity\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int intentIndex = ArrayUtils.indexOfObject(args, Intent.class, 1);\n            if (intentIndex < 0) {\n                return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;\n            }\n            int resultToIndex = ArrayUtils.indexOfObject(args, IBinder.class, 2);\n            String resolvedType = (String) args[intentIndex + 1];\n            Intent intent = (Intent) args[intentIndex];\n            intent.setDataAndType(intent.getData(), resolvedType);\n            IBinder resultTo = resultToIndex >= 0 ? (IBinder) args[resultToIndex] : null;\n            int userId = VUserHandle.myUserId();\n\n            if (ComponentUtils.isStubComponent(intent)) {\n                return method.invoke(who, args);\n            }\n\n            if (Intent.ACTION_INSTALL_PACKAGE.equals(intent.getAction())\n                    || (Intent.ACTION_VIEW.equals(intent.getAction())\n                    && \"application/vnd.android.package-archive\".equals(intent.getType()))) {\n                if (handleInstallRequest(intent)) {\n                    return 0;\n                }\n            } else if ((Intent.ACTION_UNINSTALL_PACKAGE.equals(intent.getAction())\n                    || Intent.ACTION_DELETE.equals(intent.getAction()))\n                    && \"package\".equals(intent.getScheme())) {\n\n                if (handleUninstallRequest(intent)) {\n                    return 0;\n                }\n            } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(intent.getAction()) ||\n                    MediaStore.ACTION_VIDEO_CAPTURE.equals(intent.getAction()) ||\n                    MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(intent.getAction())) {\n                handleMediaCaptureRequest(intent);\n            }\n\n            String resultWho = null;\n            int requestCode = 0;\n            Bundle options = ArrayUtils.getFirst(args, Bundle.class);\n            if (resultTo != null) {\n                resultWho = (String) args[resultToIndex + 1];\n                requestCode = (int) args[resultToIndex + 2];\n            }\n            // chooser\n            if (ChooserActivity.check(intent)) {\n                intent.setComponent(new ComponentName(getHostContext(), ChooserActivity.class));\n                intent.putExtra(Constants.EXTRA_USER_HANDLE, userId);\n                intent.putExtra(ChooserActivity.EXTRA_DATA, options);\n                intent.putExtra(ChooserActivity.EXTRA_WHO, resultWho);\n                intent.putExtra(ChooserActivity.EXTRA_REQUEST_CODE, requestCode);\n                return method.invoke(who, args);\n            }\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n                args[intentIndex - 1] = getHostPkg();\n            }\n            if (intent.getScheme() != null && intent.getScheme().equals(SCHEME_PACKAGE) && intent.getData() != null) {\n                if (intent.getAction() != null && intent.getAction().startsWith(\"android.settings.\")) {\n                    intent.setData(Uri.parse(\"package:\" + getHostPkg()));\n                }\n            }\n\n            ActivityInfo activityInfo = VirtualCore.get().resolveActivityInfo(intent, userId);\n            if (activityInfo == null) {\n                VLog.e(\"VActivityManager\", \"Unable to resolve activityInfo : %s\", intent);\n                if (intent.getPackage() != null && isAppPkg(intent.getPackage())) {\n                    return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;\n                }\n                \n                if (Build.VERSION.SDK_INT >= 30) {\n                    args[1] = VirtualCore.get().getContext().getPackageName();\n                }\n                \n                return method.invoke(who, args);\n            }\n            int res = VActivityManager.get().startActivity(intent, activityInfo, resultTo, options, resultWho, requestCode, VUserHandle.myUserId());\n            if (res != 0 && resultTo != null && requestCode > 0) {\n                VActivityManager.get().sendActivityResult(resultTo, resultWho, requestCode);\n            }\n            if (resultTo != null) {\n                ActivityClientRecord r = VActivityManager.get().getActivityRecord(resultTo);\n                if (r != null && r.activity != null) {\n                    try {\n                        TypedValue out = new TypedValue();\n                        Resources.Theme theme = r.activity.getResources().newTheme();\n                        theme.applyStyle(activityInfo.getThemeResource(), true);\n                        if (theme.resolveAttribute(android.R.attr.windowAnimationStyle, out, true)) {\n\n                            TypedArray array = theme.obtainStyledAttributes(out.data,\n                                    new int[]{\n                                            android.R.attr.activityOpenEnterAnimation,\n                                            android.R.attr.activityOpenExitAnimation\n                                    });\n\n                            r.activity.overridePendingTransition(array.getResourceId(0, 0), array.getResourceId(1, 0));\n                            array.recycle();\n                        }\n                    } catch (Throwable e) {\n                        // Ignore\n                    }\n                }\n            }\n            return res;\n        }\n\n\n        private boolean handleInstallRequest(Intent intent) {\n            IAppRequestListener listener = VirtualCore.get().getAppRequestListener();\n            if (listener != null) {\n                Uri packageUri = intent.getData();\n                String sourcePath = FileUtils.getFileFromUri(getHostContext(), packageUri);\n                try {\n                    listener.onRequestInstall(sourcePath);\n                    return true;\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n            return false;\n        }\n\n        private boolean handleUninstallRequest(Intent intent) {\n            IAppRequestListener listener = VirtualCore.get().getAppRequestListener();\n            if (listener != null) {\n                Uri packageUri = intent.getData();\n                if (SCHEME_PACKAGE.equals(packageUri.getScheme())) {\n                    String pkg = packageUri.getSchemeSpecificPart();\n                    try {\n                        listener.onRequestUninstall(pkg);\n                        return true;\n                    } catch (RemoteException e) {\n                        e.printStackTrace();\n                    }\n                }\n\n            }\n            return false;\n        }\n\n        private void handleMediaCaptureRequest(Intent intent) {\n            Uri uri = intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);\n            if (uri == null || !SCHEME_FILE.equals(uri.getScheme())) {\n                return;\n            }\n            String path = uri.getPath();\n            String newPath = NativeEngine.getRedirectedPath(path);\n            if (newPath == null) {\n                return;\n            }\n            File realFile = new File(newPath);\n            Uri newUri = Uri.fromFile(realFile);\n            intent.putExtra(MediaStore.EXTRA_OUTPUT, newUri);\n        }\n\n    }\n\n    static class StartActivities extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"startActivities\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            Intent[] intents = ArrayUtils.getFirst(args, Intent[].class);\n            String[] resolvedTypes = ArrayUtils.getFirst(args, String[].class);\n            IBinder token = null;\n            int tokenIndex = ArrayUtils.indexOfObject(args, IBinder.class, 2);\n            if (tokenIndex != -1) {\n                token = (IBinder) args[tokenIndex];\n            }\n            Bundle options = ArrayUtils.getFirst(args, Bundle.class);\n            return VActivityManager.get().startActivities(intents, resolvedTypes, token, options, VUserHandle.myUserId());\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class FinishActivity extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"finishActivity\";\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            ActivityClientRecord r = VActivityManager.get().getActivityRecord(token);\n            boolean taskRemoved = VActivityManager.get().onActivityDestroy(token);\n            if (!taskRemoved && r != null && r.activity != null && r.info.getThemeResource() != 0) {\n                try {\n                    TypedValue out = new TypedValue();\n                    Resources.Theme theme = r.activity.getResources().newTheme();\n                    theme.applyStyle(r.info.getThemeResource(), true);\n                    if (theme.resolveAttribute(android.R.attr.windowAnimationStyle, out, true)) {\n\n                        TypedArray array = theme.obtainStyledAttributes(out.data,\n                                new int[]{\n                                        android.R.attr.activityCloseEnterAnimation,\n                                        android.R.attr.activityCloseExitAnimation\n                                });\n                        r.activity.overridePendingTransition(array.getResourceId(0, 0), array.getResourceId(1, 0));\n                        array.recycle();\n                    }\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            }\n            return super.afterCall(who, method, args, result);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetCallingPackage extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getCallingPackage\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            return VActivityManager.get().getCallingPackage(token);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPackageForIntentSender extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"getPackageForIntentSender\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IInterface sender = (IInterface) args[0];\n            if (sender != null) {\n                String packageName = VActivityManager.get().getPackageForIntentSender(sender.asBinder());\n                if (packageName != null) {\n                    return packageName;\n                }\n            }\n            return super.call(who, method, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    static class PublishContentProviders extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"publishContentProviders\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetServices extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"getServices\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int maxNum = (int) args[0];\n            int flags = (int) args[1];\n            return VActivityManager.get().getServices(maxNum, flags).getList();\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GrantUriPermissionFromOwner extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"grantUriPermissionFromOwner\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class SetServiceForeground extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"setServiceForeground\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName component = (ComponentName) args[0];\n            IBinder token = (IBinder) args[1];\n            int id = (int) args[2];\n            Notification notification = (Notification) args[3];\n            boolean removeNotification = false;\n            if (args[4] instanceof Boolean) {\n                removeNotification = (boolean) args[4];\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && args[4] instanceof Integer) {\n                int flags = (int) args[4];\n                removeNotification = (flags & Service.STOP_FOREGROUND_REMOVE) != 0;\n            } else {\n                VLog.e(getClass().getSimpleName(), \"Unknown flag : \" + args[4]);\n            }\n            VNotificationManager.get().dealNotification(id, notification, getAppPkg());\n\n            /**\n             * `BaseStatusBar#updateNotification` aosp will use use\n             * `new StatusBarIcon(...notification.getSmallIcon()...)`\n             *  while in samsung SystemUI.apk ,the corresponding code comes as\n             * `new StatusBarIcon(...pkgName,notification.icon...)`\n             * the icon comes from `getSmallIcon.getResource`\n             * which will throw an exception on :x process thus crash the application\n             */\n            if (notification != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&\n                    (Build.BRAND.equalsIgnoreCase(\"samsung\") || Build.MANUFACTURER.equalsIgnoreCase(\"samsung\"))) {\n                notification.icon = getHostContext().getApplicationInfo().icon;\n                Icon icon = Icon.createWithResource(getHostPkg(), notification.icon);\n                Reflect.on(notification).call(\"setSmallIcon\", icon);\n            }\n\n            VActivityManager.get().setServiceForeground(component, token, id, notification, removeNotification);\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class UpdateDeviceOwner extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"updateDeviceOwner\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n\n    static class GetIntentForIntentSender extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getIntentForIntentSender\";\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            Intent intent = (Intent) super.afterCall(who, method, args, result);\n            if (intent != null && intent.hasExtra(\"_VA_|_intent_\")) {\n                return intent.getParcelableExtra(\"_VA_|_intent_\");\n            }\n            return intent;\n        }\n    }\n\n\n    static class UnbindFinished extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"unbindFinished\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            Intent service = (Intent) args[1];\n            boolean doRebind = (boolean) args[2];\n            VActivityManager.get().unbindFinished(token, service, doRebind);\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class StartActivityIntentSender extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"startActivityIntentSender\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class BindService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"bindService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IInterface caller = (IInterface) args[0];\n            IBinder token = (IBinder) args[1];\n            Intent service = (Intent) args[2];\n            String resolvedType = (String) args[3];\n            IServiceConnection conn = (IServiceConnection) args[4];\n            int flags = (int) args[5];\n            int userId = VUserHandle.myUserId();\n            if (isServerProcess()) {\n                userId = service.getIntExtra(\"_VA_|_user_id_\", VUserHandle.USER_NULL);\n            }\n            if (userId == VUserHandle.USER_NULL) {\n                return method.invoke(who, args);\n            }\n            ServiceInfo serviceInfo = VirtualCore.get().resolveServiceInfo(service, userId);\n            if (serviceInfo != null) {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                    service.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));\n                }\n                conn = ServiceConnectionDelegate.getDelegate(conn);\n                return VActivityManager.get().bindService(caller.asBinder(), token, service, resolvedType,\n                        conn, flags, userId);\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess() || isServerProcess();\n        }\n    }\n\n    // http://aospxref.com/android-10.0.0_r2/xref/frameworks/base/core/java/android/app/ContextImpl.java#1735\n    static class BindIsolatedService extends BindService {\n        @Override\n        public String getMethodName() {\n            return \"bindIsolatedService\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            MethodParameterUtils.replaceLastAppPkg(args);\n            return super.beforeCall(who, method, args);\n        }\n    }\n\n\n    static class StartService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"startService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IInterface appThread = (IInterface) args[0];\n            Intent service = (Intent) args[1];\n            String resolvedType = (String) args[2];\n            if (service.getComponent() != null\n                    && getHostPkg().equals(service.getComponent().getPackageName())) {\n                // for server process\n                return method.invoke(who, args);\n            }\n            int userId = VUserHandle.myUserId();\n            if (service.getBooleanExtra(\"_VA_|_from_inner_\", false)) {\n                userId = service.getIntExtra(\"_VA_|_user_id_\", userId);\n                service = service.getParcelableExtra(\"_VA_|_intent_\");\n            } else {\n                if (isServerProcess()) {\n                    userId = service.getIntExtra(\"_VA_|_user_id_\", VUserHandle.USER_NULL);\n                }\n            }\n            service.setDataAndType(service.getData(), resolvedType);\n            ServiceInfo serviceInfo = VirtualCore.get().resolveServiceInfo(service, VUserHandle.myUserId());\n            if (serviceInfo != null) {\n                if (isFiltered(service)) {\n                    return service.getComponent();\n                }\n                return VActivityManager.get().startService(appThread, service, resolvedType, userId);\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess() || isServerProcess();\n        }\n\n        private boolean isFiltered(Intent service) {\n            // disable tinker.\n            if (service != null && service.getComponent() != null\n                    && EncodeUtils.decode(\"Y29tLnRlbmNlbnQudGlua2VyLmxpYi5zZXJ2aWMuVGlua2VyUGF0Y2hTZXJ2aWNl\") // com.tencent.tinker.lib.service.TinkerPatchService\n                    .equals(service.getComponent().getClassName())) {\n                return true;\n            }\n            return false;\n        }\n    }\n\n    static class StartActivityAndWait extends StartActivity {\n        @Override\n        public String getMethodName() {\n            return \"startActivityAndWait\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class PublishService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"publishService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            if (!VActivityManager.get().isVAServiceToken(token)) {\n                return method.invoke(who, args);\n            }\n            Intent intent = (Intent) args[1];\n            IBinder service = (IBinder) args[2];\n            VActivityManager.get().publishService(token, intent, service);\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    static class GetRunningAppProcesses extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getRunningAppProcesses\";\n        }\n\n        @Override\n        public synchronized Object call(Object who, Method method, Object... args) throws Throwable {\n            List<ActivityManager.RunningAppProcessInfo> infoList = (List<ActivityManager.RunningAppProcessInfo>) method\n                    .invoke(who, args);\n            if (infoList != null) {\n                for (ActivityManager.RunningAppProcessInfo info : infoList) {\n                    if (VActivityManager.get().isAppPid(info.pid)) {\n                        List<String> pkgList = VActivityManager.get().getProcessPkgList(info.pid);\n                        String processName = VActivityManager.get().getAppProcessName(info.pid);\n                        if (processName != null) {\n                            info.processName = processName;\n                        }\n                        info.pkgList = pkgList.toArray(new String[pkgList.size()]);\n                        info.uid = VUserHandle.getAppId(VActivityManager.get().getUidByPid(info.pid));\n                    }\n                }\n            }\n            return infoList;\n        }\n    }\n\n\n    static class SetPackageAskScreenCompat extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"setPackageAskScreenCompat\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (args.length > 0 && args[0] instanceof String) {\n                    args[0] = getHostPkg();\n                }\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetCallingActivity extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getCallingActivity\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            return VActivityManager.get().getCallingActivity(token);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetCurrentUser extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getCurrentUser\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            try {\n                return UserInfo.ctor.newInstance(0, \"user\", VUserInfo.FLAG_PRIMARY);\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n    }\n\n\n    static class KillApplicationProcess extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"killApplicationProcess\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (args.length > 1 && args[0] instanceof String && args[1] instanceof Integer) {\n                String processName = (String) args[0];\n                int uid = (int) args[1];\n                VActivityManager.get().killApplicationProcess(processName, uid);\n                return 0;\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class StartActivityAsUser extends StartActivity {\n\n        @Override\n        public String getMethodName() {\n            return \"startActivityAsUser\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class CheckPermission extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"checkPermission\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String permission = (String) args[0];\n            if (SpecialComponentList.isWhitePermission(permission)) {\n                return PackageManager.PERMISSION_GRANTED;\n            }\n            if (permission.startsWith(\"com.google\")) {\n                return PackageManager.PERMISSION_GRANTED;\n            }\n            args[args.length - 1] = getRealUid();\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n\n    static class StartActivityAsCaller extends StartActivity {\n\n        @Override\n        public String getMethodName() {\n            return \"startActivityAsCaller\";\n        }\n    }\n\n\n    static class HandleIncomingUser extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"handleIncomingUser\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int lastIndex = args.length - 1;\n            if (args[lastIndex] instanceof String) {\n                args[lastIndex] = getHostPkg();\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    static class GetTasks extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getTasks\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            List<ActivityManager.RunningTaskInfo> runningTaskInfos = (List<ActivityManager.RunningTaskInfo>) method\n                    .invoke(who, args);\n            for (ActivityManager.RunningTaskInfo info : runningTaskInfos) {\n                AppTaskInfo taskInfo = VActivityManager.get().getTaskInfo(info.id);\n                if (taskInfo != null) {\n                    info.topActivity = taskInfo.topActivity;\n                    info.baseActivity = taskInfo.baseActivity;\n                }\n            }\n            return runningTaskInfos;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPersistedUriPermissions extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPersistedUriPermissions\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class RegisterReceiver extends MethodProxy {\n        protected int mIIntentReceiverIndex = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1\n                ? 2\n                : 1;\n\n        protected int mRequiredPermissionIndex = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1\n                ? 4\n                : 3;\n        protected int mIntentFilterIndex = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1\n                ? 3\n                : 2;\n\n        private WeakHashMap<IBinder, IIntentReceiver> mProxyIIntentReceivers = new WeakHashMap<>();\n\n        @Override\n        public String getMethodName() {\n            return \"registerReceiver\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            args[mRequiredPermissionIndex] = null;\n            IntentFilter filter = (IntentFilter) args[mIntentFilterIndex];\n            SpecialComponentList.protectIntentFilter(filter);\n            if (args.length > mIIntentReceiverIndex && IIntentReceiver.class.isInstance(args[mIIntentReceiverIndex])) {\n                final IInterface old = (IInterface) args[mIIntentReceiverIndex];\n                if (!IIntentReceiverProxy.class.isInstance(old)) {\n                    final IBinder token = old.asBinder();\n                    if (token != null) {\n                        token.linkToDeath(new IBinder.DeathRecipient() {\n                            @Override\n                            public void binderDied() {\n                                token.unlinkToDeath(this, 0);\n                                mProxyIIntentReceivers.remove(token);\n                            }\n                        }, 0);\n                        IIntentReceiver proxyIIntentReceiver = mProxyIIntentReceivers.get(token);\n                        if (proxyIIntentReceiver == null) {\n                            proxyIIntentReceiver = new IIntentReceiverProxy(old);\n                            mProxyIIntentReceivers.put(token, proxyIIntentReceiver);\n                        }\n                        WeakReference mDispatcher = LoadedApk.ReceiverDispatcher.InnerReceiver.mDispatcher.get(old);\n                        if (mDispatcher != null) {\n                            LoadedApk.ReceiverDispatcher.mIIntentReceiver.set(mDispatcher.get(), proxyIIntentReceiver);\n                            args[mIIntentReceiverIndex] = proxyIIntentReceiver;\n                        }\n                    }\n                }\n            }\n            return method.invoke(who, args);\n        }\n\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n        private static class IIntentReceiverProxy extends IIntentReceiver.Stub {\n\n            IInterface mOld;\n\n            IIntentReceiverProxy(IInterface old) {\n                this.mOld = old;\n            }\n\n            public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered,\n                                       boolean sticky, int sendingUser) throws RemoteException {\n                if (!accept(intent)) {\n                    return;\n                }\n                if (intent.hasExtra(\"_VA_|_intent_\")) {\n                    intent = intent.getParcelableExtra(\"_VA_|_intent_\");\n                }\n                SpecialComponentList.unprotectIntent(intent);\n                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {\n                    IIntentReceiverJB.performReceive.call(mOld, intent, resultCode, data, extras, ordered, sticky, sendingUser);\n                } else {\n                    mirror.android.content.IIntentReceiver.performReceive.call(mOld, intent, resultCode, data, extras, ordered, sticky);\n                }\n            }\n\n            private boolean accept(Intent intent) {\n                int uid = intent.getIntExtra(\"_VA_|_uid_\", -1);\n                if (uid != -1) {\n                    return VClientImpl.get().getVUid() == uid;\n                }\n                int userId = intent.getIntExtra(\"_VA_|_user_id_\", -1);\n                return userId == -1 || userId == VUserHandle.myUserId();\n            }\n\n            @SuppressWarnings(\"unused\")\n            public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered,\n                                       boolean sticky) throws RemoteException {\n                this.performReceive(intent, resultCode, data, extras, ordered, sticky, 0);\n            }\n\n        }\n    }\n\n\n    static class StopService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"stopService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IInterface caller = (IInterface) args[0];\n            Intent intent = (Intent) args[1];\n            String resolvedType = (String) args[2];\n            intent.setDataAndType(intent.getData(), resolvedType);\n            ComponentName componentName = intent.getComponent();\n            PackageManager pm = VirtualCore.getPM();\n            if (componentName == null) {\n                ResolveInfo resolveInfo = pm.resolveService(intent, 0);\n                if (resolveInfo != null && resolveInfo.serviceInfo != null) {\n                    componentName = new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);\n                }\n            }\n            if (componentName != null && !getHostPkg().equals(componentName.getPackageName())) {\n                return VActivityManager.get().stopService(caller, intent, resolvedType);\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess() || isServerProcess();\n        }\n    }\n\n\n    static class GetContentProvider extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getContentProvider\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int nameIdx = getProviderNameIndex();\n            String name = (String) args[nameIdx];\n            int userId = VUserHandle.myUserId();\n            ProviderInfo info = VPackageManager.get().resolveContentProvider(name, 0, userId);\n            if (info != null && info.enabled && isAppPkg(info.packageName)) {\n                int targetVPid = VActivityManager.get().initProcess(info.packageName, info.processName, userId);\n                if (targetVPid == -1) {\n                    return null;\n                }\n                args[nameIdx] = VASettings.getStubAuthority(targetVPid);\n                \n                if (Build.VERSION.SDK_INT >= 30) {\n                    args[1] = VirtualCore.get().getContext().getPackageName();\n                }\n                \n                Object holder = method.invoke(who, args);\n                if (holder == null) {\n                    return null;\n                }\n                if (BuildCompat.isOreo()) {\n                    IInterface provider = ContentProviderHolderOreo.provider.get(holder);\n                    if (provider != null) {\n                        provider = VActivityManager.get().acquireProviderClient(userId, info);\n                    }\n                    ContentProviderHolderOreo.provider.set(holder, provider);\n                    ContentProviderHolderOreo.info.set(holder, info);\n                } else {\n                    IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);\n                    if (provider != null) {\n                        provider = VActivityManager.get().acquireProviderClient(userId, info);\n                    }\n                    IActivityManager.ContentProviderHolder.provider.set(holder, provider);\n                    IActivityManager.ContentProviderHolder.info.set(holder, info);\n                }\n                return holder;\n            }\n\n            if (BuildCompat.isQ()) {\n                int packageIndex = getPackageIndex();\n                if (packageIndex > 0 && args[packageIndex] instanceof String) {\n                    args[packageIndex] = getHostPkg();\n                }\n            }\n            Object holder = method.invoke(who, args);\n            if (holder != null) {\n                if (BuildCompat.isOreo()) {\n                    IInterface provider = ContentProviderHolderOreo.provider.get(holder);\n                    info = ContentProviderHolderOreo.info.get(holder);\n                    if (provider != null) {\n                        provider = ProviderHook.createProxy(true, info.authority, provider);\n                    }\n                    ContentProviderHolderOreo.provider.set(holder, provider);\n                } else {\n                    IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);\n                    info = IActivityManager.ContentProviderHolder.info.get(holder);\n                    if (provider != null) {\n                        provider = ProviderHook.createProxy(true, info.authority, provider);\n                    }\n                    IActivityManager.ContentProviderHolder.provider.set(holder, provider);\n                }\n                return holder;\n            }\n            return null;\n        }\n\n\n        public int getProviderNameIndex() {\n            if (BuildCompat.isQ()) {\n                return 2;\n            }\n            return 1;\n        }\n\n        public int getPackageIndex() {\n            if (BuildCompat.isQ()) {\n                return 1;\n            }\n            return -1;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    static class SetTaskDescription extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"setTaskDescription\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ActivityManager.TaskDescription td = (ActivityManager.TaskDescription) args[1];\n            String label = td.getLabel();\n            Bitmap icon = td.getIcon();\n\n            // If the activity label/icon isn't specified, the application's label/icon is shown instead\n            // Android usually does that for us, but in this case we want info about the contained app, not VIrtualApp itself\n            if (label == null || icon == null) {\n                Application app = VClientImpl.get().getCurrentApplication();\n                if (app != null) {\n                    try {\n                        if (label == null) {\n                            label = app.getApplicationInfo().loadLabel(app.getPackageManager()).toString();\n                        }\n                        if (icon == null) {\n                            Drawable drawable = app.getApplicationInfo().loadIcon(app.getPackageManager());\n                            if (drawable != null) {\n                                icon = DrawableUtils.drawableToBitMap(drawable);\n                            }\n                        }\n                        td = new ActivityManager.TaskDescription(label, icon, td.getPrimaryColor());\n                    } catch (Throwable e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n\n            TaskDescriptionDelegate descriptionDelegate = VirtualCore.get().getTaskDescriptionDelegate();\n            if (descriptionDelegate != null) {\n                td = descriptionDelegate.getTaskDescription(td);\n            }\n\n            args[1] = td;\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class StopServiceToken extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"stopServiceToken\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName componentName = (ComponentName) args[0];\n            IBinder token = (IBinder) args[1];\n            if (!VActivityManager.get().isVAServiceToken(token)) {\n                return method.invoke(who, args);\n            }\n            int startId = (int) args[2];\n            if (componentName != null) {\n                return VActivityManager.get().stopServiceToken(componentName, token, startId);\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess() || isServerProcess();\n        }\n    }\n\n    static class StartActivityWithConfig extends StartActivity {\n        @Override\n        public String getMethodName() {\n            return \"startActivityWithConfig\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return super.call(who, method, args);\n        }\n    }\n\n    static class StartNextMatchingActivity extends StartActivity {\n        @Override\n        public String getMethodName() {\n            return \"startNextMatchingActivity\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return false;\n        }\n    }\n\n\n    static class BroadcastIntent extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"broadcastIntent\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            Intent intent = (Intent) args[1];\n            String type = (String) args[2];\n            intent.setDataAndType(intent.getData(), type);\n            if (VirtualCore.get().getComponentDelegate() != null) {\n                VirtualCore.get().getComponentDelegate().onSendBroadcast(intent);\n            }\n            Intent newIntent = handleIntent(intent);\n            if (newIntent != null) {\n                args[1] = newIntent;\n            } else {\n                return 0;\n            }\n\n            if (args[7] instanceof String || args[7] instanceof String[]) {\n                // clear the permission\n                args[7] = null;\n            }\n            return method.invoke(who, args);\n        }\n\n\n        private Intent handleIntent(final Intent intent) {\n            final String action = intent.getAction();\n            if (\"android.intent.action.CREATE_SHORTCUT\".equals(action)\n                    || \"com.android.launcher.action.INSTALL_SHORTCUT\".equals(action)) {\n\n                return VASettings.ENABLE_INNER_SHORTCUT ? handleInstallShortcutIntent(intent) : null;\n\n            } else if (\"com.android.launcher.action.UNINSTALL_SHORTCUT\".equals(action)) {\n\n                handleUninstallShortcutIntent(intent);\n\n            } else if (BadgerManager.handleBadger(intent)) {\n                return null;\n            } else if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) {\n                // intent send to system, do not modify it's action(may have other same intent)\n                return handleMediaScannerIntent(intent);\n            } else {\n                return ComponentUtils.redirectBroadcastIntent(intent, VUserHandle.myUserId());\n            }\n            return intent;\n        }\n\n        private Intent handleMediaScannerIntent(Intent intent) {\n            if (intent == null) {\n                return null;\n            }\n            Uri data = intent.getData();\n            if (data == null) {\n                return intent;\n            }\n            String scheme = data.getScheme();\n            if (!\"file\".equalsIgnoreCase(scheme)) {\n                return intent;\n            }\n            String path = data.getPath();\n            if (path == null) {\n                return intent;\n            }\n            String newPath = NativeEngine.getRedirectedPath(path);\n            File newFile = new File(newPath);\n            if (!newFile.exists()) {\n                return intent;\n            }\n            intent.setData(Uri.fromFile(newFile));\n            return intent;\n        }\n\n        private Intent handleInstallShortcutIntent(Intent intent) {\n            Intent shortcut = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);\n            if (shortcut != null) {\n                ComponentName component = shortcut.resolveActivity(VirtualCore.getPM());\n                if (component != null) {\n                    String pkg = component.getPackageName();\n                    Intent newShortcutIntent = new Intent();\n                    newShortcutIntent.setClassName(getHostPkg(), Constants.SHORTCUT_PROXY_ACTIVITY_NAME);\n                    newShortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);\n                    newShortcutIntent.putExtra(\"_VA_|_intent_\", shortcut);\n                    newShortcutIntent.putExtra(\"_VA_|_uri_\", shortcut.toUri(0));\n                    newShortcutIntent.putExtra(\"_VA_|_user_id_\", VUserHandle.myUserId());\n                    intent.removeExtra(Intent.EXTRA_SHORTCUT_INTENT);\n                    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, newShortcutIntent);\n\n                    Intent.ShortcutIconResource icon = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);\n                    if (icon != null && !TextUtils.equals(icon.packageName, getHostPkg())) {\n                        try {\n                            Resources resources = VirtualCore.get().getResources(pkg);\n                            int resId = resources.getIdentifier(icon.resourceName, \"drawable\", pkg);\n                            if (resId > 0) {\n                                //noinspection deprecation\n                                Drawable iconDrawable = resources.getDrawable(resId);\n                                Bitmap newIcon = BitmapUtils.drawableToBitmap(iconDrawable);\n                                if (newIcon != null) {\n                                    intent.removeExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);\n                                    intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, newIcon);\n                                }\n                            }\n                        } catch (Throwable e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n            return intent;\n        }\n\n        private void handleUninstallShortcutIntent(Intent intent) {\n            Intent shortcut = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);\n            if (shortcut != null) {\n                ComponentName componentName = shortcut.resolveActivity(getPM());\n                if (componentName != null) {\n                    Intent newShortcutIntent = new Intent();\n                    newShortcutIntent.putExtra(\"_VA_|_uri_\", shortcut.toUri(0));\n                    newShortcutIntent.setClassName(getHostPkg(), Constants.SHORTCUT_PROXY_ACTIVITY_NAME);\n                    newShortcutIntent.removeExtra(Intent.EXTRA_SHORTCUT_INTENT);\n                    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, newShortcutIntent);\n                }\n            }\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetActivityClassForToken extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getActivityClassForToken\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            return VActivityManager.get().getActivityForToken(token);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class CheckGrantUriPermission extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"checkGrantUriPermission\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class ServiceDoneExecuting extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"serviceDoneExecuting\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            IBinder token = (IBinder) args[0];\n            if (!VActivityManager.get().isVAServiceToken(token)) {\n                return method.invoke(who, args);\n            }\n            int type = (int) args[1];\n            int startId = (int) args[2];\n            int res = (int) args[3];\n            VActivityManager.get().serviceDoneExecuting(token, type, startId, res);\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GetPackageProcessState extends ReplaceLastPkgMethodProxy {\n        public GetPackageProcessState() {\n            super(\"getPackageProcessState\");\n        }\n    }\n\n    // For Android 11\n    static class RegisterReceiverWithFeature extends RegisterReceiver {\n        public RegisterReceiverWithFeature() {\n            if (BuildCompat.isS()) {\n                // http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/android/app/IActivityManager.aidl?fi=IActivityManager#127\n                mIIntentReceiverIndex = 4;\n                mIntentFilterIndex = 5;\n                mRequiredPermissionIndex = 6;\n            } else {\n                // http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/android/app/IActivityManager.aidl?fi=IActivityManager#124\n                mIIntentReceiverIndex = 3;\n                mIntentFilterIndex = 4;\n                mRequiredPermissionIndex = 5;\n            }\n        }\n\n        @Override\n        public String getMethodName() {\n            return \"registerReceiverWithFeature\";\n        }\n    }\n\n    static class GetIntentSenderWithFeature extends GetIntentSender {\n\n        public GetIntentSenderWithFeature() {\n            // http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/android/app/IActivityManager.aidl?fi=IActivityManager#245\n            mIntentIndex = 6;\n            mResolvedTypesIndex = 7;\n            mFlagsIndex = 8;\n        }\n\n        @Override\n        public String getMethodName() {\n            return \"getIntentSenderWithFeature\";\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/am/TransactionHandlerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.am;\n\nimport android.app.ClientTransactionHandler;\nimport android.app.TransactionHandlerProxy;\nimport android.util.Log;\n\nimport com.lody.virtual.client.interfaces.IInjector;\n\nimport java.lang.reflect.Field;\n\nimport mirror.android.app.ActivityThread;\n\n/**\n * @author weishu\n * @date 2018/8/7.\n */\npublic class TransactionHandlerStub implements IInjector {\n    private static final String TAG = \"TransactionHandlerStub\";\n\n    @Override\n    public void inject() throws Throwable {\n        Log.i(TAG, \"inject transaction handler.\");\n        Object activityThread = ActivityThread.currentActivityThread.call();\n        Object transactionExecutor = ActivityThread.mTransactionExecutor.get(activityThread);\n\n        Field mTransactionHandlerField = transactionExecutor.getClass().getDeclaredField(\"mTransactionHandler\");\n        mTransactionHandlerField.setAccessible(true);\n        ClientTransactionHandler original = (ClientTransactionHandler) mTransactionHandlerField.get(transactionExecutor);\n        TransactionHandlerProxy proxy = new TransactionHandlerProxy(original);\n\n        mTransactionHandlerField.set(transactionExecutor, proxy);\n        Log.i(TAG, \"executor's handler: \" + mTransactionHandlerField.get(transactionExecutor));\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/appops/AppOpsManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.appops;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\n\nimport java.lang.reflect.Method;\n\nimport mirror.com.android.internal.app.IAppOpsService;\n\n/**\n * @author Lody\n *         <p>\n *         Fuck the AppOpsService.\n * @see android.app.AppOpsManager\n */\n@TargetApi(Build.VERSION_CODES.KITKAT)\npublic class AppOpsManagerStub extends BinderInvocationProxy {\n\n    public AppOpsManagerStub() {\n        super(IAppOpsService.Stub.asInterface, Context.APP_OPS_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new BaseMethodProxy(\"checkOperation\", 1, 2));\n        addMethodProxy(new BaseMethodProxy(\"noteOperation\", 1, 2));\n        addMethodProxy(new BaseMethodProxy(\"startOperation\", 2, 3));\n        addMethodProxy(new BaseMethodProxy(\"finishOperation\", 2, 3));\n        addMethodProxy(new BaseMethodProxy(\"startWatchingMode\", -1, 1));\n        addMethodProxy(new BaseMethodProxy(\"checkPackage\", 0, 1));\n        addMethodProxy(new BaseMethodProxy(\"getOpsForPackage\", 0, 1));\n        addMethodProxy(new BaseMethodProxy(\"setMode\", 1, 2));\n        addMethodProxy(new BaseMethodProxy(\"checkAudioOperation\", 2, 3));\n        addMethodProxy(new BaseMethodProxy(\"setAudioRestriction\", 2, -1));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"resetAllModes\"));\n        addMethodProxy(new MethodProxy() {\n            @Override\n            public String getMethodName() {\n                return \"noteProxyOperation\";\n            }\n\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                return 0;\n            }\n        });\n    }\n\n    private class BaseMethodProxy extends StaticMethodProxy {\n        final int pkgIndex;\n        final int uidIndex;\n\n        BaseMethodProxy(String name, int uidIndex, int pkgIndex) {\n            super(name);\n            this.pkgIndex = pkgIndex;\n            this.uidIndex = uidIndex;\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            if (pkgIndex != -1 && args.length > pkgIndex && args[pkgIndex] instanceof String) {\n                args[pkgIndex] = getHostPkg();\n            }\n            if (uidIndex != -1 && args[uidIndex] instanceof Integer) {\n                args[uidIndex] = getRealUid();\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/appwidget/AppWidgetManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.appwidget;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport mirror.com.android.internal.appwidget.IAppWidgetService;\n\n/**\n * @author Lody\n *\n * @see android.appwidget.AppWidgetManager\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class AppWidgetManagerStub extends BinderInvocationProxy {\n\n\tpublic AppWidgetManagerStub() {\n\t\tsuper(IAppWidgetService.Stub.asInterface, Context.APPWIDGET_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"startListening\", new int[0]));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"stopListening\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"allocateAppWidgetId\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"deleteAppWidgetId\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"deleteHost\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"deleteAllHosts\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getAppWidgetViews\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getAppWidgetIdsForHost\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"createAppWidgetConfigIntentSender\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"updateAppWidgetIds\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"updateAppWidgetOptions\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getAppWidgetOptions\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"partiallyUpdateAppWidgetIds\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"updateAppWidgetProvider\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"notifyAppWidgetViewDataChanged\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getInstalledProvidersForProfile\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getAppWidgetInfo\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"hasBindAppWidgetPermission\", false));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"setBindAppWidgetPermission\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"bindAppWidgetId\", false));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"bindRemoteViewsService\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"unbindRemoteViewsService\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getAppWidgetIds\", new int[0]));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"isBoundWidgetPackage\", false));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/audio/AudioManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.audio;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport mirror.android.media.IAudioService;\n\n/**\n * @author Lody\n *\n * @see android.media.AudioManager\n */\n\npublic class AudioManagerStub extends BinderInvocationProxy {\n\tpublic AudioManagerStub() {\n\t\tsuper(IAudioService.Stub.asInterface, Context.AUDIO_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"adjustVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"adjustLocalOrRemoteStreamVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"adjustSuggestedStreamVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"adjustStreamVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"adjustMasterVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setStreamVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setMasterVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setMicrophoneMute\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setRingerModeExternal\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setRingerModeInternal\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setMode\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"avrcpSupportsAbsoluteVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"abandonAudioFocus\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"requestAudioFocus\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setWiredDeviceConnectionState\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setSpeakerphoneOn\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"setBluetoothScoOn\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"stopBluetoothSco\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"startBluetoothSco\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"disableSafeMediaVolume\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"registerRemoteControlClient\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"unregisterAudioFocusClient\"));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/backup/BackupManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.backup;\n\nimport android.app.backup.BackupManager;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport mirror.android.app.backup.IBackupManager;\n\n/**\n * @author Lody\n *\n * @see BackupManager\n */\npublic class BackupManagerStub extends BinderInvocationProxy {\n\tpublic BackupManagerStub() {\n\t\tsuper(IBackupManager.Stub.asInterface, \"backup\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"dataChanged\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"clearBackupData\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"agentConnected\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"agentDisconnected\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"restoreAtInstall\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"setBackupEnabled\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"setBackupProvisioned\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"backupNow\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"fullBackup\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"fullTransportBackup\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"fullRestore\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"acknowledgeFullBackupOrRestore\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getCurrentTransport\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"listAllTransports\", new String[0]));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"selectBackupTransport\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"isBackupEnabled\", false));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"setBackupPassword\", true));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"hasBackupPassword\", false));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"beginRestoreSession\", null));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/battery/BatteryStatsStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.battery;\n\nimport android.content.Context;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastUidMethodProxy;\n\nimport mirror.com.android.internal.os.health.SystemHealthManager;\n\n/**\n * @author weishu\n * @date 2020/11/24.\n */\npublic class BatteryStatsStub extends BinderInvocationProxy {\n\n    public BatteryStatsStub() {\n        super(getInterface(), \"batterystats\");\n    }\n\n    private static IInterface getInterface() {\n        Object manager = VirtualCore.get().getContext().getSystemService(Context.SYSTEM_HEALTH_SERVICE);\n        return SystemHealthManager.mBatteryStats.get(manager);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n\n        addMethodProxy(new ReplaceLastUidMethodProxy(\"takeUidSnapshot\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/bluetooth/BluetoothStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.bluetooth;\n\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.helper.utils.marks.FakeDeviceMark;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.bluetooth.IBluetooth;\n\n/**\n * @see android.bluetooth.BluetoothManager\n */\npublic class BluetoothStub extends BinderInvocationProxy {\n    public static final String SERVICE_NAME = Build.VERSION.SDK_INT >= 17 ?\n            \"bluetooth_manager\" :\n            \"bluetooth\";\n\n    public BluetoothStub() {\n        super(IBluetooth.Stub.asInterface, SERVICE_NAME);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new GetAddress());\n    }\n\n    @FakeDeviceMark(\"fake MAC\")\n    private static class GetAddress extends StaticMethodProxy {\n\n        GetAddress() {\n            super(\"getAddress\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return getDeviceInfo().bluetoothMac;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/clipboard/ClipBoardStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.clipboard;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.utils.DeviceUtil;\n\nimport mirror.android.content.ClipboardManager;\nimport mirror.android.content.ClipboardManagerOreo;\n\n/**\n * @author Lody\n * @see ClipboardManager\n */\npublic class ClipBoardStub extends BinderInvocationProxy {\n\n    public ClipBoardStub() {\n        super(getInterface(), Context.CLIPBOARD_SERVICE);\n    }\n\n    private static IInterface getInterface() {\n        if (isOreo()) {\n            android.content.ClipboardManager cm = (android.content.ClipboardManager)\n                    VirtualCore.get().getContext().getSystemService(Context.CLIPBOARD_SERVICE);\n            return ClipboardManagerOreo.mService.get(cm);\n        } else {\n            return ClipboardManager.getService.call();\n        }\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getPrimaryClip\"));\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"setPrimaryClip\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"getPrimaryClipDescription\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"hasPrimaryClip\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"addPrimaryClipChangedListener\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"removePrimaryClipChangedListener\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"hasClipboardText\"));\n        }\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        super.inject();\n        if (isOreo()) {\n            android.content.ClipboardManager cm = (android.content.ClipboardManager)\n                    VirtualCore.get().getContext().getSystemService(Context.CLIPBOARD_SERVICE);\n            ClipboardManagerOreo.mService.set(cm, getInvocationStub().getProxyInterface());\n        } else {\n            ClipboardManager.sService.set(getInvocationStub().getProxyInterface());\n        }\n    }\n\n    private static boolean isOreo() {\n        return BuildCompat.isOreo() &&\n                !DeviceUtil.isSamsung()\n                || ClipboardManager.getService == null;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/connectivity/ConnectivityStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.connectivity;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.ipc.ServiceManagerNative;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.net.IConnectivityManager;\n\n/**\n * @author legency\n */\npublic class ConnectivityStub extends BinderInvocationProxy {\n\n    public ConnectivityStub() {\n        super(IConnectivityManager.Stub.asInterface, Context.CONNECTIVITY_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/content/ContentServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.content;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\n\nimport mirror.android.content.IContentService;\n\n/**\n * @author Lody\n * @see IContentService\n */\n@Inject(MethodProxies.class)\npublic class ContentServiceStub extends BinderInvocationProxy {\n\n    public ContentServiceStub() {\n        super(IContentService.Stub.asInterface, \"content\");\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/content/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.content;\n\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.hook.base.MethodProxy;\n\nimport java.lang.reflect.Method;\n\n/**\n * author: weishu on 18/3/13.\n */\nclass MethodProxies {\n\n    static class NotifyChange extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"notifyChange\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return super.beforeCall(who, method, args);\n            }\n            ApplicationInfo currentApplicationInfo = VClientImpl.get().getCurrentApplicationInfo();\n            if (currentApplicationInfo == null) {\n                return super.beforeCall(who, method, args);\n            }\n            int targetSdkVersion = currentApplicationInfo.targetSdkVersion;\n\n            int length = args.length;\n            int index = -1;\n            for (int i = 0; i < length; i++) {\n                Object obj = args[length - 1];\n                if (obj != null && obj.getClass() == Integer.class) {\n                    if ((int) obj == targetSdkVersion) {\n                        index = i;\n                    }\n                }\n            }\n            /*\n            In ContentService, it contains this code:\n\n            if (targetSdkVersion >= Build.VERSION_CODES.O) {\n                throw new SecurityException(msg);\n            } else {\n                if (msg.startsWith(\"Failed to find provider\")) {\n                    // Sigh, we need to quietly let apps targeting older API\n                    // levels notify on non-existent providers.\n                } else {\n                    Log.w(TAG, \"Ignoring notify for \" + uri + \" from \" + uid + \": \" + msg);\n                    return;\n                }\n            }\n            we just modify the targetSdkVersion dynamic to fake it.\n            */\n            if (index != -1) {\n                args[index] = Build.VERSION_CODES.N_MR1;\n            }\n\n            return super.beforeCall(who, method, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/context_hub/ContextHubServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.context_hub;\n\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport mirror.android.hardware.location.IContextHubService;\n\npublic class ContextHubServiceStub extends BinderInvocationProxy {\n\n    public ContextHubServiceStub() {\n        super(IContextHubService.Stub.asInterface, getServiceName());\n    }\n\n    private static String getServiceName() {\n        return Build.VERSION.SDK_INT >= 26 ? \"contexthub\" : \"contexthub_service\";\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ResultStaticMethodProxy(\"registerCallback\", 0));\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/devicepolicy/DevicePolicyManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.devicepolicy;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.admin.IDevicePolicyManager;\n\n/**\n * Created by wy on 2017/10/20.\n */\n\npublic class DevicePolicyManagerStub extends BinderInvocationProxy{\n    public DevicePolicyManagerStub() {\n        super(IDevicePolicyManager.Stub.asInterface, Context.DEVICE_POLICY_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new GetStorageEncryptionStatus());\n    }\n\n    private static class GetStorageEncryptionStatus extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getStorageEncryptionStatus\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            args[0] = VirtualCore.get().getHostPkg();\n            return method.invoke(who, args);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/display/DisplayStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.display;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport mirror.android.hardware.display.DisplayManagerGlobal;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class DisplayStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {\n\tpublic DisplayStub() {\n\t\tsuper(new MethodInvocationStub<IInterface>(\n\t\t\t\tDisplayManagerGlobal.mDm.get(DisplayManagerGlobal.getInstance.call())));\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"createVirtualDisplay\"));\n\t}\n\n\t@Override\n\tpublic void inject() throws Throwable {\n\t\tObject dmg = DisplayManagerGlobal.getInstance.call();\n\t\tDisplayManagerGlobal.mDm.set(dmg, getInvocationStub().getProxyInterface());\n\t}\n\n\t@Override\n\tpublic boolean isEnvBad() {\n\t\tObject dmg = DisplayManagerGlobal.getInstance.call();\n\t\tIInterface mDm = DisplayManagerGlobal.mDm.get(dmg);\n\t\treturn mDm != getInvocationStub().getProxyInterface();\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/dropbox/DropBoxManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.dropbox;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport mirror.com.android.internal.os.IDropBoxManagerService;\n\n/**\n * @author Lody\n */\npublic class DropBoxManagerStub extends BinderInvocationProxy {\n\tpublic DropBoxManagerStub() {\n\t\tsuper(IDropBoxManagerService.Stub.asInterface, Context.DROPBOX_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getNextEntry\", null));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/fingerprint/FingerprintManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.fingerprint;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport mirror.android.hardware.fingerprint.IFingerprintService;\n\n/**\n * Created by natsuki on 12/10/2017.\n */\n\n@TargetApi(Build.VERSION_CODES.M)\npublic class FingerprintManagerStub extends BinderInvocationProxy {\n    public FingerprintManagerStub() {\n        super(IFingerprintService.Stub.asInterface, Context.FINGERPRINT_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"isHardwareDetected\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"hasEnrolledFingerprints\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"authenticate\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"cancelAuthentication\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getEnrolledFingerprints\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getAuthenticatorId\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/graphics/GraphicsStatsStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.graphics;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport mirror.android.view.IGraphicsStats;\n\n\n/**\n * @author Lody\n */\npublic class GraphicsStatsStub extends BinderInvocationProxy {\n\n\tpublic GraphicsStatsStub() {\n\t\tsuper(IGraphicsStats.Stub.asInterface, \"graphicsstats\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"requestBufferForProcess\"));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/imms/MmsStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.imms;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceSpecPkgMethodProxy;\n\nimport mirror.com.android.internal.telephony.IMms;\n\n\n/**\n * @author Lody\n */\npublic class MmsStub extends BinderInvocationProxy {\n\n\tpublic MmsStub() {\n\t\tsuper(IMms.Stub.asInterface, \"imms\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\taddMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendMessage\", 1));\n\t\taddMethodProxy(new ReplaceSpecPkgMethodProxy(\"downloadMessage\", 1));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"importTextMessage\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"importMultimediaMessage\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"deleteStoredMessage\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"deleteStoredConversation\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"updateStoredMessageStatus\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"archiveStoredConversation\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"addTextMessageDraft\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"addMultimediaMessageDraft\"));\n\t\taddMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendStoredMessage\", 1));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"setAutoPersisting\"));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/input/InputMethodManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.input;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\n\nimport mirror.com.android.internal.view.inputmethod.InputMethodManager;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n\npublic class InputMethodManagerStub extends BinderInvocationProxy {\n\n\tpublic InputMethodManagerStub() {\n\t\tsuper(\n\t\t\t\tInputMethodManager.mService.get(\n\t\t\t\t\t\tVirtualCore.get().getContext().getSystemService(Context.INPUT_METHOD_SERVICE)),\n\t\t\t\tContext.INPUT_METHOD_SERVICE);\n\t}\n\n\t@Override\n\tpublic void inject() throws Throwable {\n\t\tObject inputMethodManager = getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n\t\tInputMethodManager.mService.set(inputMethodManager, getInvocationStub().getProxyInterface());\n\t\tgetInvocationStub().replaceService(Context.INPUT_METHOD_SERVICE);\n\t}\n\n\n\t@Override\n\tpublic boolean isEnvBad() {\n\t\tObject inputMethodManager = getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n\t\treturn InputMethodManager\n\t\t\t\t.mService.get(inputMethodManager) != getInvocationStub().getBaseInterface();\n\t}\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/input/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.input;\n\nimport android.view.inputmethod.EditorInfo;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\nclass MethodProxies {\n\n    static class StartInput extends StartInputOrWindowGainedFocus {\n\n        @Override\n        public String getMethodName() {\n            return \"startInput\";\n        }\n    }\n\n    static class WindowGainedFocus extends StartInputOrWindowGainedFocus {\n\n        @Override\n        public String getMethodName() {\n            return \"windowGainedFocus\";\n        }\n\n\n    }\n\n    static class StartInputOrWindowGainedFocus extends MethodProxy {\n\n\n        @Override\n        public String getMethodName() {\n            return \"startInputOrWindowGainedFocus\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int editorInfoIndex = ArrayUtils.indexOfFirst(args, EditorInfo.class);\n            if (editorInfoIndex != -1) {\n                EditorInfo attribute = (EditorInfo) args[editorInfoIndex];\n                attribute.packageName = getHostPkg();\n            }\n            return method.invoke(who, args);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/isms/ISmsStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.isms;\n\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceSpecPkgMethodProxy;\n\nimport mirror.com.android.internal.telephony.ISms;\n\n/**\n * @author Lody\n */\n\npublic class ISmsStub extends BinderInvocationProxy {\n\n    public ISmsStub() {\n        super(ISms.Stub.asInterface, \"isms\");\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"getAllMessagesFromIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"updateMessageOnIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"copyMessageToIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendDataForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendDataForSubscriberWithSelfPermissions\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendTextForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendTextForSubscriberWithSelfPermissions\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendMultipartTextForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendStoredText\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendStoredMultipartText\", 1));\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getAllMessagesFromIccEf\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"getAllMessagesFromIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"updateMessageOnIccEf\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"updateMessageOnIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"copyMessageToIccEf\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"copyMessageToIccEfForSubscriber\", 1));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendData\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendDataForSubscriber\", 1));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendText\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendTextForSubscriber\", 1));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendMultipartText\"));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendMultipartTextForSubscriber\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendStoredText\", 1));\n            addMethodProxy(new ReplaceSpecPkgMethodProxy(\"sendStoredMultipartText\", 1));\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getAllMessagesFromIccEf\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"updateMessageOnIccEf\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"copyMessageToIccEf\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendData\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendText\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"sendMultipartText\"));\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/isub/ISubStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.isub;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport mirror.com.android.internal.telephony.ISub;\n\n/**\n * @author Lody\n */\npublic class ISubStub extends BinderInvocationProxy {\n\n    public ISubStub() {\n        super(ISub.Stub.asInterface, \"isub\");\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getAllSubInfoList\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getAllSubInfoCount\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getActiveSubscriptionInfo\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getActiveSubscriptionInfoForIccId\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getActiveSubscriptionInfoForSimSlotIndex\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getActiveSubscriptionInfoList\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getActiveSubInfoCount\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"getSubscriptionProperty\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/job/JobServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.job;\n\nimport android.annotation.TargetApi;\nimport android.app.job.JobInfo;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.ipc.VJobScheduler;\nimport com.lody.virtual.helper.utils.ComponentUtils;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.job.IJobScheduler;\nimport mirror.android.app.job.JobWorkItem;\n\n/**\n * @author Lody\n *\n * @see android.app.job.JobScheduler\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class JobServiceStub extends BinderInvocationProxy {\n\n\tpublic JobServiceStub() {\n\t\tsuper(IJobScheduler.Stub.asInterface, Context.JOB_SCHEDULER_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new schedule());\n\t\taddMethodProxy(new getAllPendingJobs());\n\t\taddMethodProxy(new cancelAll());\n\t\taddMethodProxy(new cancel());\n\n\t\tif (Build.VERSION.SDK_INT >= 24) {\n\t\t\taddMethodProxy(new getPendingJob());\n\t\t}\n\t\tif (Build.VERSION.SDK_INT >= 26) {\n\t\t\taddMethodProxy(new enqueue());\n\t\t}\n\t}\n\n\tprivate class getPendingJob extends MethodProxy {\n\t\tprivate getPendingJob() {\n\t\t}\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn VJobScheduler.get().getPendingJob((Integer) args[0]);\n\t\t}\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getPendingJob\";\n\t\t}\n\t}\n\n\tprivate class enqueue extends MethodProxy {\n\t\tprivate enqueue() {\n\t\t}\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn VJobScheduler.get().enqueue(\n\t\t\t\t\t(JobInfo) args[0],\n\t\t\t\t\tJobServiceStub.this.redirect(args[1], MethodProxy.getAppPkg())\n\t\t\t);\n\t\t}\n\t\tpublic String getMethodName() {\n\t\t\treturn \"enqueue\";\n\t\t}\n\t}\n\n\tprivate Object redirect(Object item, String pkg) {\n\t\tif (item == null) {\n\t\t\treturn null;\n\t\t}\n\t\tIntent redirectIntentSender = ComponentUtils.redirectIntentSender(4, pkg, (Intent) JobWorkItem.getIntent.call(item, new Object[0]), null);\n\t\tObject newInstance = JobWorkItem.ctor.newInstance(redirectIntentSender);\n\t\tJobWorkItem.mWorkId.set(newInstance, JobWorkItem.mWorkId.get(item));\n\t\tJobWorkItem.mGrants.set(newInstance, JobWorkItem.mGrants.get(item));\n\t\tJobWorkItem.mDeliveryCount.set(newInstance, JobWorkItem.mDeliveryCount.get(item));\n\t\treturn newInstance;\n\t}\n\n\tprivate class schedule extends MethodProxy {\n\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"schedule\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tJobInfo jobInfo = (JobInfo) args[0];\n\t\t\treturn VJobScheduler.get().schedule(jobInfo);\n\t\t}\n\t}\n\n\tprivate class getAllPendingJobs extends MethodProxy {\n\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"getAllPendingJobs\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\treturn VJobScheduler.get().getAllPendingJobs();\n\t\t}\n\t}\n\n\tprivate class cancelAll extends MethodProxy {\n\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"cancelAll\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tVJobScheduler.get().cancelAll();\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate class cancel extends MethodProxy {\n\n\t\t@Override\n\t\tpublic String getMethodName() {\n\t\t\treturn \"cancel\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\tint jobId = (int) args[0];\n\t\t\tVJobScheduler.get().cancel(jobId);\n\t\t\treturn 0;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/libcore/LibCoreStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.libcore;\n\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceUidMethodProxy;\n\nimport mirror.libcore.io.ForwardingOs;\nimport mirror.libcore.io.Libcore;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic class LibCoreStub extends MethodInvocationProxy<MethodInvocationStub<Object>> {\n\n    public LibCoreStub() {\n        super(new MethodInvocationStub<Object>(getOs()));\n    }\n\n    private static Object getOs() {\n        Object os = Libcore.os.get();\n        if (ForwardingOs.os != null) {\n            Object posix = ForwardingOs.os.get(os);\n            if (posix != null) {\n                os = posix;\n            }\n        }\n        return os;\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceUidMethodProxy(\"chown\", 1));\n        addMethodProxy(new ReplaceUidMethodProxy(\"fchown\", 1));\n        addMethodProxy(new ReplaceUidMethodProxy(\"getpwuid\", 0));\n        addMethodProxy(new ReplaceUidMethodProxy(\"lchown\", 1));\n        addMethodProxy(new ReplaceUidMethodProxy(\"setuid\", 0));\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        Libcore.os.set(getInvocationStub().getProxyInterface());\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return getOs() != getInvocationStub().getProxyInterface();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/libcore/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.libcore;\n\nimport com.lody.virtual.client.NativeEngine;\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.helper.utils.Reflect;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport mirror.libcore.io.Os;\n\n/**\n * @author Lody\n */\n\nclass MethodProxies {\n\n    static class Lstat extends Stat {\n\n        @Override\n        public String getMethodName() {\n            return \"lstat\";\n        }\n    }\n\n    static class Getpwnam extends MethodProxy {\n            @Override\n            public String getMethodName() {\n                return \"getpwnam\";\n            }\n\n            @Override\n            public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n                if (result != null) {\n                    Reflect pwd = Reflect.on(result);\n                    int uid = pwd.get(\"pw_uid\");\n                    if (uid == VirtualCore.get().myUid()) {\n                        pwd.set(\"pw_uid\", VClientImpl.get().getVUid());\n                    }\n                }\n                return result;\n            }\n        }\n\n    static class GetUid extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getuid\";\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            int uid = (int) result;\n            return NativeEngine.onGetUid(uid);\n        }\n    }\n\n    static class GetsockoptUcred extends MethodProxy {\n            @Override\n            public String getMethodName() {\n                return \"getsockoptUcred\";\n            }\n\n            @Override\n            public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n                if (result != null) {\n                    Reflect ucred = Reflect.on(result);\n                    int uid = ucred.get(\"uid\");\n                    if (uid == VirtualCore.get().myUid()) {\n                        ucred.set(\"uid\", getBaseVUid());\n                    }\n                }\n                return result;\n            }\n        }\n\n    static class Stat extends MethodProxy {\n\n        private static Field st_uid;\n\n        static {\n            try {\n                Method stat = Os.TYPE.getMethod(\"stat\", String.class);\n                Class<?> StructStat = stat.getReturnType();\n                st_uid = StructStat.getDeclaredField(\"st_uid\");\n                st_uid.setAccessible(true);\n            } catch (Throwable e) {\n                throw new IllegalStateException(e);\n            }\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            int uid = (int) st_uid.get(result);\n            if (uid == VirtualCore.get().myUid()) {\n                st_uid.set(result, getBaseVUid());\n            }\n            return result;\n        }\n\n        @Override\n        public String getMethodName() {\n            return \"stat\";\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/GPSListenerThread.java",
    "content": "package com.lody.virtual.client.hook.proxies.location;\n\nimport android.location.Location;\nimport android.os.Build.VERSION;\nimport android.os.Handler;\n\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.remote.vloc.VLocation;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\nimport mirror.android.location.LocationManager;\n\n\npublic class GPSListenerThread extends TimerTask {\n    private static GPSListenerThread INSTANCE;\n    private Handler handler = new Handler();\n    private boolean isRunning = false;\n    private HashMap<Object, Long> listeners = new HashMap<>();\n    private Timer timer = new Timer();\n\n    static {\n        INSTANCE = new GPSListenerThread();\n    }\n\n    private void notifyGPSStatus(Map listeners) {\n        if (listeners != null && !listeners.isEmpty()) {\n            //noinspection unchecked\n            Set<Map.Entry> entries = listeners.entrySet();\n            for (Map.Entry entry : entries) {\n                try {\n                    Object value = entry.getValue();\n                    if (value != null) {\n                        MockLocationHelper.invokeSvStatusChanged(value);\n                    }\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    private void notifyLocation(Map listeners) {\n        if (listeners != null) {\n            try {\n                if (!listeners.isEmpty()) {\n                    VLocation vLocation = VirtualLocationManager.get().getLocation();\n                    if (vLocation != null) {\n                        Location location = vLocation.toSysLocation();\n                        //noinspection unchecked\n                        Set<Map.Entry> entries = listeners.entrySet();\n                        for (Map.Entry entry : entries) {\n                            Object value = entry.getValue();\n                            if (value != null) {\n                                try {\n                                    LocationManager.ListenerTransport.onLocationChanged.call(value, location);\n                                } catch (Throwable e) {\n                                    e.printStackTrace();\n                                }\n                            }\n                        }\n                    }\n                }\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private void notifyMNmeaListener(Map listeners) {\n        if (listeners != null && !listeners.isEmpty()) {\n            //noinspection unchecked\n            Set<Map.Entry> entries = listeners.entrySet();\n            for (Map.Entry entry : entries) {\n                try {\n                    Object value = entry.getValue();\n                    if (value != null) {\n                        MockLocationHelper.invokeNmeaReceived(value);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    public void addListenerTransport(Object transport) {\n        this.listeners.put(transport, System.currentTimeMillis());\n        if (!isRunning) {\n            synchronized (this) {\n                if (!isRunning) {\n                    isRunning = true;\n                    timer.schedule(this, 1000, 1000);\n                }\n            }\n        }\n    }\n\n    public void removeListenerTransport(Object transport) {\n        if (transport != null) {\n            listeners.remove(transport);\n        }\n    }\n\n    public void run() {\n        if (!listeners.isEmpty()) {\n            if (VirtualLocationManager.get().getMode() == VirtualLocationManager.MODE_CLOSE) {\n                listeners.clear();\n                return;\n            }\n            for (Map.Entry entry : this.listeners.entrySet()) {\n                try {\n                    Object transport = entry.getKey();\n                    Map gpsStatusListeners;\n                    if (VERSION.SDK_INT >= 24) {\n                        Map nmeaListeners = LocationManager.mGnssNmeaListeners.get(transport);\n                        notifyGPSStatus(LocationManager.mGnssStatusListeners.get(transport));\n                        notifyMNmeaListener(nmeaListeners);\n                        gpsStatusListeners = LocationManager.mGpsStatusListeners.get(transport);\n                        notifyGPSStatus(gpsStatusListeners);\n                        notifyMNmeaListener(LocationManager.mGpsNmeaListeners.get(transport));\n                    } else {\n                        gpsStatusListeners = LocationManager.mGpsStatusListeners.get(transport);\n                        notifyGPSStatus(gpsStatusListeners);\n                        notifyMNmeaListener(LocationManager.mNmeaListeners.get(transport));\n                    }\n                    final Map listeners = LocationManager.mListeners.get(transport);\n                    if (gpsStatusListeners != null && !gpsStatusListeners.isEmpty()) {\n                        if (listeners == null || listeners.isEmpty()) {\n                            // listeners not ready\n                            handler.postDelayed(new Runnable() {\n                                public void run() {\n                                    GPSListenerThread.this.notifyLocation(listeners);\n                                }\n                            }, 100);\n                        } else {\n                            notifyLocation(listeners);\n                        }\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    public void stop() {\n        this.timer.cancel();\n    }\n\n    public static GPSListenerThread get() {\n        return INSTANCE;\n    }\n\n    private GPSListenerThread() {\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/GPSStatusListenerThread.java",
    "content": "package com.lody.virtual.client.hook.proxies.location;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\npublic class GPSStatusListenerThread extends TimerTask {\n    private static GPSStatusListenerThread INSTANCE;\n    private boolean isRunning = false;\n    private Map<Object, Long> listeners = new HashMap<>();\n    private Timer timer = new Timer();\n\n    static {\n        INSTANCE = new GPSStatusListenerThread();\n    }\n\n    public void addListenerTransport(Object transport) {\n        if (!isRunning) {\n            synchronized (this) {\n                if (!isRunning) {\n                    isRunning = true;\n                    timer.schedule(this, 100, 800);\n                }\n            }\n        }\n        listeners.put(transport, System.currentTimeMillis());\n    }\n\n    public void removeListenerTransport(Object obj) {\n        if (obj != null) {\n            listeners.remove(obj);\n        }\n    }\n\n    public void run() {\n        if (!listeners.isEmpty()) {\n            for (Entry entry : listeners.entrySet()) {\n                try {\n                    Object transport = entry.getKey();\n                    MockLocationHelper.invokeSvStatusChanged(transport);\n                    MockLocationHelper.invokeNmeaReceived(transport);\n                } catch (Throwable e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    public void stop() {\n        timer.cancel();\n    }\n\n    public static GPSStatusListenerThread get() {\n        return INSTANCE;\n    }\n\n    private GPSStatusListenerThread() {\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/LocationManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.location;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.LogInvocation;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.stub.VASettings;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.location.ILocationManager;\n\n/**\n * @author Lody\n * @see android.location.LocationManager\n */\n@LogInvocation(LogInvocation.Condition.ALWAYS)\n@Inject(MethodProxies.class)\npublic class LocationManagerStub extends BinderInvocationProxy {\n    public LocationManagerStub() {\n        super(ILocationManager.Stub.asInterface, Context.LOCATION_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"addTestProvider\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"removeTestProvider\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"setTestProviderLocation\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"clearTestProviderLocation\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"setTestProviderEnabled\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"clearTestProviderEnabled\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"setTestProviderStatus\"));\n            addMethodProxy(new ReplaceLastPkgMethodProxy(\"clearTestProviderStatus\"));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"addGpsMeasurementsListener\", true));\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"addGpsNavigationMessageListener\", true));\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"removeGpsMeasurementListener\", 0));\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"removeGpsNavigationMessageListener\", 0));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"requestGeofence\", 0));\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"removeGeofence\", 0));\n        }\n\n        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"addProximityAlert\", 0));\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"addNmeaListener\", 0));\n            addMethodProxy(new FakeReplaceLastPkgMethodProxy(\"removeNmeaListener\", 0));\n        }\n    }\n\n    private static class FakeReplaceLastPkgMethodProxy extends ReplaceLastPkgMethodProxy {\n        private Object mDefValue;\n\n        private FakeReplaceLastPkgMethodProxy(String name, Object def) {\n            super(name);\n            mDefValue = def;\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return mDefValue;\n            }\n            return super.call(who, method, args);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.location;\n\nimport android.location.LocationManager;\nimport android.location.LocationRequest;\nimport android.os.Build;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.remote.vloc.VLocation;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport mirror.android.location.LocationRequestL;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"ALL\")\npublic class MethodProxies {\n\n    private static void fixLocationRequest(LocationRequest request) {\n        if (request != null) {\n            if (LocationRequestL.mHideFromAppOps != null) {\n                LocationRequestL.mHideFromAppOps.set(request, false);\n            }\n            if (LocationRequestL.mWorkSource != null) {\n                LocationRequestL.mWorkSource.set(request, null);\n            }\n        }\n    }\n\n    static class AddGpsStatusListener extends ReplaceLastPkgMethodProxy {\n\n        public AddGpsStatusListener() {\n            super(\"addGpsStatusListener\");\n        }\n\n        public AddGpsStatusListener(String name) {\n            super(name);\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                Object transport = ArrayUtils.getFirst(args, mirror.android.location.LocationManager.GpsStatusListenerTransport.TYPE);\n                Object locationManager = mirror.android.location.LocationManager.GpsStatusListenerTransport.this$0.get(transport);\n                mirror.android.location.LocationManager.GpsStatusListenerTransport.onGpsStarted.call(transport);\n                mirror.android.location.LocationManager.GpsStatusListenerTransport.onFirstFix.call(transport, 0);\n                if (mirror.android.location.LocationManager.GpsStatusListenerTransport.mListener.get(transport) != null) {\n                    MockLocationHelper.invokeSvStatusChanged(transport);\n                } else {\n                    MockLocationHelper.invokeNmeaReceived(transport);\n                }\n                GPSListenerThread.get().addListenerTransport(locationManager);\n                return true;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class RequestLocationUpdates extends ReplaceLastPkgMethodProxy {\n\n        public RequestLocationUpdates() {\n            super(\"requestLocationUpdates\");\n        }\n\n        @Override\n        public Object call(final Object who, Method method, Object... args) throws Throwable {\n            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {\n                LocationRequest request = (LocationRequest) args[0];\n                fixLocationRequest(request);\n            }\n            if (isFakeLocationEnable()) {\n                Object transport = ArrayUtils.getFirst(args, mirror.android.location.LocationManager.ListenerTransport.TYPE);\n                if (transport != null) {\n                    Object locationManager = mirror.android.location.LocationManager.ListenerTransport.this$0.get(transport);\n                    MockLocationHelper.setGpsStatus(locationManager);\n                    GPSListenerThread.get().addListenerTransport(locationManager);\n                }\n                return 0;\n            }\n            \n            if (Build.VERSION.SDK_INT >= 30) {\n                args[3] = VirtualCore.get().getContext().getPackageName();\n            }\n            \n            return super.call(who, method, args);\n        }\n    }\n\n    static class RemoveUpdates extends ReplaceLastPkgMethodProxy {\n\n        public RemoveUpdates() {\n            super(\"removeUpdates\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                // TODO\n                return 0;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class GetLastLocation extends ReplaceLastPkgMethodProxy {\n\n        public GetLastLocation() {\n            super(\"getLastLocation\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (!(args[0] instanceof String)) {\n                LocationRequest request = (LocationRequest) args[0];\n                fixLocationRequest(request);\n            }\n            if (isFakeLocationEnable()) {\n                VLocation loc = VirtualLocationManager.get().getLocation();\n                if (loc != null) {\n                    return loc.toSysLocation();\n                } else {\n                    return null;\n                }\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class GetLastKnownLocation extends GetLastLocation {\n        @Override\n        public String getMethodName() {\n            return \"getLastKnownLocation\";\n        }\n    }\n\n    static class getProviders extends MethodProxy {\n\n        static List PROVIDERS = Arrays.asList(\n                LocationManager.GPS_PROVIDER,\n                LocationManager.PASSIVE_PROVIDER,\n                LocationManager.NETWORK_PROVIDER\n        );\n\n        @Override\n        public String getMethodName() {\n            return \"getProviders\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return PROVIDERS;\n        }\n    }\n\n    static class IsProviderEnabled extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"isProviderEnabled\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                String provider = (String) args[0];\n                if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {\n                    return true;\n                }\n                if (LocationManager.GPS_PROVIDER.equals(provider)) {\n                    return true;\n                }\n                if (LocationManager.NETWORK_PROVIDER.equals(provider)) {\n                    return true;\n                }\n                return false;\n\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class getAllProviders extends getProviders {\n\n        @Override\n        public String getMethodName() {\n            return \"getAllProviders\";\n        }\n    }\n\n    static class GetBestProvider extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"getBestProvider\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return LocationManager.GPS_PROVIDER;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class RemoveGpsStatusListener extends ReplaceLastPkgMethodProxy {\n        public RemoveGpsStatusListener() {\n            super(\"removeGpsStatusListener\");\n        }\n\n        public RemoveGpsStatusListener(String name) {\n            super(name);\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return 0;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class sendExtraCommand extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"sendExtraCommand\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return true;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class UnregisterGnssStatusCallback extends RemoveGpsStatusListener {\n        public UnregisterGnssStatusCallback() {\n            super(\"unregisterGnssStatusCallback\");\n        }\n    }\n\n    static class RegisterGnssStatusCallback extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"registerGnssStatusCallback\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            if (!isFakeLocationEnable()) {\n                return super.call(who, method, args);\n            }\n            Object transport = ArrayUtils.getFirst(args, mirror.android.location.LocationManager.GnssStatusListenerTransport.TYPE);\n            if (transport != null) {\n                mirror.android.location.LocationManager.GnssStatusListenerTransport.onGnssStarted.call(transport, new Object[0]);\n                if (mirror.android.location.LocationManager.GnssStatusListenerTransport.mGpsListener.get(transport) != null) {\n                    MockLocationHelper.invokeSvStatusChanged(transport);\n                } else {\n                    MockLocationHelper.invokeNmeaReceived(transport);\n                }\n                mirror.android.location.LocationManager.GnssStatusListenerTransport.onFirstFix.call(transport, Integer.valueOf(0));\n                Object locationManager = mirror.android.location.LocationManager.GnssStatusListenerTransport.this$0.get(transport);\n                GPSListenerThread.get().addListenerTransport(locationManager);\n            }\n            return true;\n        }\n    }\n\n    static class getProviderProperties extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getProviderProperties\";\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return super.afterCall(who, method, args, result);\n            }\n            try {\n                Reflect.on(result).set(\"mRequiresNetwork\", false);\n                Reflect.on(result).set(\"mRequiresCell\", false);\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n            return result;\n        }\n    }\n\n    static class locationCallbackFinished extends MethodProxy {\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return true;\n            }\n            return super.call(who, method, args);\n        }\n\n        @Override\n        public String getMethodName() {\n            return \"locationCallbackFinished\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/location/MockLocationHelper.java",
    "content": "package com.lody.virtual.client.hook.proxies.location;\n\nimport android.util.Log;\n\nimport com.lody.virtual.client.env.VirtualGPSSatalines;\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.remote.vloc.VLocation;\n\nimport java.lang.reflect.Method;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\nimport mirror.android.location.LocationManager;\n\n/**\n * @author Lody\n */\npublic class MockLocationHelper {\n\n    public static void invokeNmeaReceived(Object listener) {\n        if (listener != null) {\n            VirtualGPSSatalines satalines = VirtualGPSSatalines.get();\n            try {\n                VLocation location = VirtualLocationManager.get().getLocation();\n                if (location != null) {\n                    String date = new SimpleDateFormat(\"HHmmss:SS\", Locale.US).format(new Date());\n                    String lat = getGPSLat(location.latitude);\n                    String lon = getGPSLat(location.longitude);\n                    String latNW = getNorthWest(location);\n                    String lonSE = getSouthEast(location);\n                    String $GPGGA = checksum(String.format(\"$GPGGA,%s,%s,%s,%s,%s,1,%s,692,.00,M,.00,M,,,\", date, lat, latNW, lon, lonSE, satalines.getSvCount()));\n                    String $GPRMC = checksum(String.format(\"$GPRMC,%s,A,%s,%s,%s,%s,0,0,260717,,,A,\", date, lat, latNW, lon, lonSE));\n                    if (LocationManager.GnssStatusListenerTransport.onNmeaReceived != null) {\n                        LocationManager.GnssStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPGSV,1,1,04,12,05,159,36,15,41,087,15,19,38,262,30,31,56,146,19,*73\");\n                        LocationManager.GnssStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), $GPGGA);\n                        LocationManager.GnssStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPVTG,0,T,0,M,0,N,0,K,A,*25\");\n                        LocationManager.GnssStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), $GPRMC);\n                        LocationManager.GnssStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPGSA,A,2,12,15,19,31,,,,,,,,,604,712,986,*27\");\n                    } else if (LocationManager.GpsStatusListenerTransport.onNmeaReceived != null) {\n                        LocationManager.GpsStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPGSV,1,1,04,12,05,159,36,15,41,087,15,19,38,262,30,31,56,146,19,*73\");\n                        LocationManager.GpsStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), $GPGGA);\n                        LocationManager.GpsStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPVTG,0,T,0,M,0,N,0,K,A,*25\");\n                        LocationManager.GpsStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), $GPRMC);\n                        LocationManager.GpsStatusListenerTransport.onNmeaReceived.call(listener, System.currentTimeMillis(), \"$GPGSA,A,2,12,15,19,31,,,,,,,,,604,712,986,*27\");\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static void setGpsStatus(Object locationManager) {\n\n        VirtualGPSSatalines satalines = VirtualGPSSatalines.get();\n        Method setStatus = null;\n        int svCount = satalines.getSvCount();\n        float[] snrs = satalines.getSnrs();\n        int[] prns = satalines.getPrns();\n        float[] elevations = satalines.getElevations();\n        float[] azimuths = satalines.getAzimuths();\n        Object mGpsStatus = Reflect.on(locationManager).get(\"mGpsStatus\");\n        try {\n            setStatus = mGpsStatus.getClass().getDeclaredMethod(\"setStatus\", Integer.TYPE, int[].class, float[].class, float[].class, float[].class, Integer.TYPE, Integer.TYPE, Integer.TYPE);\n            setStatus.setAccessible(true);\n            int ephemerisMask = satalines.getEphemerisMask();\n            int almanacMask = satalines.getAlmanacMask();\n            int usedInFixMask = satalines.getUsedInFixMask();\n            setStatus.invoke(mGpsStatus, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);\n        } catch (Exception e) {\n            // ignore\n        }\n        if (setStatus == null) {\n            try {\n                setStatus = mGpsStatus.getClass().getDeclaredMethod(\"setStatus\", Integer.TYPE, int[].class, float[].class, float[].class, float[].class, int[].class, int[].class, int[].class);\n                setStatus.setAccessible(true);\n                svCount = satalines.getSvCount();\n                int length = satalines.getPrns().length;\n                elevations = satalines.getElevations();\n                azimuths = satalines.getAzimuths();\n                int[] ephemerisMask = new int[length];\n                for (int i = 0; i < length; i++) {\n                    ephemerisMask[i] = satalines.getEphemerisMask();\n                }\n                int[] almanacMask = new int[length];\n                for (int i = 0; i < length; i++) {\n                    almanacMask[i] = satalines.getAlmanacMask();\n                }\n                int[] usedInFixMask = new int[length];\n                for (int i = 0; i < length; i++) {\n                    usedInFixMask[i] = satalines.getUsedInFixMask();\n                }\n                setStatus.invoke(mGpsStatus, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static void invokeSvStatusChanged(Object transport) {\n        if (transport != null) {\n            VirtualGPSSatalines satalines = VirtualGPSSatalines.get();\n            try {\n                Class<?> aClass = transport.getClass();\n                int svCount;\n                float[] snrs;\n                float[] elevations;\n                float[] azimuths;\n                if (aClass == LocationManager.GnssStatusListenerTransport.TYPE) {\n                    svCount = satalines.getSvCount();\n                    int[] prnWithFlags = satalines.getPrnWithFlags();\n                    snrs = satalines.getSnrs();\n                    elevations = satalines.getElevations();\n                    azimuths = satalines.getAzimuths();\n                    LocationManager.GnssStatusListenerTransport.onSvStatusChanged.call(transport, svCount, prnWithFlags, snrs, elevations, azimuths);\n                } else if (aClass == LocationManager.GpsStatusListenerTransport.TYPE) {\n                    svCount = satalines.getSvCount();\n                    int[] prns = satalines.getPrns();\n                    snrs = satalines.getSnrs();\n                    elevations = satalines.getElevations();\n                    azimuths = satalines.getAzimuths();\n                    int ephemerisMask = satalines.getEphemerisMask();\n                    int almanacMask = satalines.getAlmanacMask();\n                    int usedInFixMask = satalines.getUsedInFixMask();\n                    if (LocationManager.GpsStatusListenerTransport.onSvStatusChanged != null) {\n                        LocationManager.GpsStatusListenerTransport.onSvStatusChanged.call(transport, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);\n                    } else if (LocationManager.GpsStatusListenerTransportVIVO.onSvStatusChanged != null) {\n                        LocationManager.GpsStatusListenerTransportVIVO.onSvStatusChanged.call(transport, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask, new long[svCount]);\n                    } else if (LocationManager.GpsStatusListenerTransportSumsungS5.onSvStatusChanged != null) {\n                        LocationManager.GpsStatusListenerTransportSumsungS5.onSvStatusChanged.call(transport, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask, new int[svCount]);\n                    } else if (LocationManager.GpsStatusListenerTransportOPPO_R815T.onSvStatusChanged != null) {\n                        int len = prns.length;\n                        int[] ephemerisMasks = new int[len];\n                        for (int i = 0; i < len; i++) {\n                            ephemerisMasks[i] = satalines.getEphemerisMask();\n                        }\n                        int[] almanacMasks = new int[len];\n                        for (int i = 0; i < len; i++) {\n                            almanacMasks[i] = satalines.getAlmanacMask();\n                        }\n                        int[] usedInFixMasks = new int[len];\n                        for (int i = 0; i < len; i++) {\n                            usedInFixMasks[i] = satalines.getUsedInFixMask();\n                        }\n                        LocationManager.GpsStatusListenerTransportOPPO_R815T.onSvStatusChanged.call(transport, svCount, prns, snrs, elevations, azimuths, ephemerisMasks, almanacMasks, usedInFixMasks, svCount);\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private static String getSouthEast(VLocation location) {\n        if (location.longitude > 0.0d) {\n            return \"E\";\n        }\n        return \"W\";\n    }\n\n    private static String getNorthWest(VLocation location) {\n        if (location.latitude > 0.0d) {\n            return \"N\";\n        }\n        return \"S\";\n    }\n\n    public static String getGPSLat(double v) {\n        int du = (int) v;\n        double fen = (v - (double) du) * 60.0d;\n        return du + leftZeroPad((int) fen, 2) + \":\" + String.valueOf(fen).substring(2);\n    }\n\n    private static String leftZeroPad(int num, int size) {\n        return leftZeroPad(String.valueOf(num), size);\n    }\n\n    private static String leftZeroPad(String num, int size) {\n        StringBuilder sb = new StringBuilder(size);\n        int i;\n        if (num == null) {\n            for (i = 0; i < size; i++) {\n                sb.append('0');\n            }\n        } else {\n            for (i = 0; i < size - num.length(); i++) {\n                sb.append('0');\n            }\n            sb.append(num);\n        }\n        return sb.toString();\n    }\n\n    public static String checksum(String nema) {\n        String checkStr = nema;\n        if (nema.startsWith(\"$\")) {\n            checkStr = nema.substring(1);\n        }\n        int sum = 0;\n        for (int i = 0; i < checkStr.length(); i++) {\n            sum ^= (byte) checkStr.charAt(i);\n        }\n        return nema + \"*\" + String.format(\"%02X\", sum).toLowerCase();\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/media/router/MediaRouterServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.media.router;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport mirror.android.media.IMediaRouterService;\n\n/**\n * @author Lody\n * @see android.media.MediaRouter\n */\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN)\npublic class MediaRouterServiceStub extends BinderInvocationProxy {\n\n    public MediaRouterServiceStub() {\n        super(IMediaRouterService.Stub.asInterface, Context.MEDIA_ROUTER_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"registerClientAsUser\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/media/session/SessionManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.media.session;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport mirror.android.media.session.ISessionManager;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class SessionManagerStub extends BinderInvocationProxy {\n\n\tpublic SessionManagerStub() {\n\t\tsuper(ISessionManager.Stub.asInterface, Context.MEDIA_SESSION_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"createSession\"));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.mount;\n\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\n\nimport java.io.File;\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\nclass MethodProxies {\n\n    static class GetVolumeList extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getVolumeList\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            if (args == null || args.length == 0) {\n                return super.beforeCall(who, method, args);\n            }\n            if (args[0] instanceof Integer) {\n                args[0] = getRealUid();\n            }\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return super.beforeCall(who, method, args);\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            return result;\n        }\n    }\n\n    static class Mkdirs extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"mkdirs\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return super.beforeCall(who, method, args);\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\n                return super.call(who, method, args);\n            }\n            String path;\n            if (args.length == 1) {\n                path = (String) args[0];\n            } else {\n                path = (String) args[1];\n            }\n            File file = new File(path);\n            if (!file.exists() && !file.mkdirs()) {\n                return -1;\n            }\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MountServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.mount;\n\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport mirror.RefStaticMethod;\nimport mirror.android.os.mount.IMountService;\nimport mirror.android.os.storage.IStorageManager;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic class MountServiceStub extends BinderInvocationProxy {\n\n    public MountServiceStub() {\n        super(getInterfaceMethod(), \"mount\");\n    }\n\n    private static RefStaticMethod<IInterface> getInterfaceMethod() {\n        if (BuildCompat.isOreo()) {\n            return IStorageManager.Stub.asInterface;\n        } else {\n            return IMountService.Stub.asInterface;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/network/NetworkManagementStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.network;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceUidMethodProxy;\n\nimport mirror.android.os.INetworkManagementService;\n\n@TargetApi(Build.VERSION_CODES.M)\npublic class\nNetworkManagementStub extends BinderInvocationProxy {\n\n\tpublic NetworkManagementStub() {\n\t\tsuper(INetworkManagementService.Stub.asInterface, \"network_management\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceUidMethodProxy(\"setUidCleartextNetworkPolicy\", 0));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/notification/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.notification;\n\nimport android.app.Notification;\nimport android.os.Build;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport com.lody.virtual.client.ipc.VNotificationManager;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\n@SuppressWarnings(\"unused\")\nclass MethodProxies {\n\n    static class EnqueueNotification extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"enqueueNotification\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            int notificationIndex = ArrayUtils.indexOfFirst(args, Notification.class);\n            int idIndex = ArrayUtils.indexOfFirst(args, Integer.class);\n            int id = (int) args[idIndex];\n            id = VNotificationManager.get().dealNotificationId(id, pkg, null, getAppUserId());\n            args[idIndex] = id;\n            Notification notification = (Notification) args[notificationIndex];\n            if (!VNotificationManager.get().dealNotification(id, notification, pkg)) {\n                return 0;\n            }\n            VNotificationManager.get().addNotification(id, null, pkg, getAppUserId());\n            args[0] = getHostPkg();\n            return method.invoke(who, args);\n        }\n    }\n\n    /* package */ static class EnqueueNotificationWithTag extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"enqueueNotificationWithTag\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            int notificationIndex = ArrayUtils.indexOfFirst(args, Notification.class);\n            int idIndex = ArrayUtils.indexOfFirst(args, Integer.class);\n            int tagIndex = (Build.VERSION.SDK_INT >= 18 ? 2 : 1);\n            int id = (int) args[idIndex];\n            String tag = (String) args[tagIndex];\n\n            id = VNotificationManager.get().dealNotificationId(id, pkg, tag, getAppUserId());\n            tag = VNotificationManager.get().dealNotificationTag(id, pkg, tag, getAppUserId());\n            args[idIndex] = id;\n            args[tagIndex] = tag;\n            //key(tag,id)\n            Notification notification = (Notification) args[notificationIndex];\n            if (!VNotificationManager.get().dealNotification(id, notification, pkg)) {\n                return 0;\n            }\n            VNotificationManager.get().addNotification(id, tag, pkg, getAppUserId());\n            args[0] = getHostPkg();\n            if (Build.VERSION.SDK_INT >= 18 && args[1] instanceof String) {\n                args[1] = getHostPkg();\n            }\n            return method.invoke(who, args);\n        }\n    }\n\n    /* package */ static class EnqueueNotificationWithTagPriority extends EnqueueNotificationWithTag {\n\n        @Override\n        public String getMethodName() {\n            return \"enqueueNotificationWithTagPriority\";\n        }\n    }\n\n    /* package */ static class CancelNotificationWithTag extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"cancelNotificationWithTag\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = MethodParameterUtils.replaceFirstAppPkg(args);\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            \n            int index_tag = 1;\n            int index_id = 2;\n\n            if (Build.VERSION.SDK_INT >= 30) {\n                index_tag = 2;\n                index_id = 3;\n            }\n            \n            String tag = (String) args[index_tag];\n            int id = (int) args[index_id];\n\n            id = VNotificationManager.get().dealNotificationId(id, pkg, tag, getAppUserId());\n            tag = VNotificationManager.get().dealNotificationTag(id, pkg, tag, getAppUserId());\n\n            args[index_tag] = tag;\n            args[index_id] = id;\n            return method.invoke(who, args);\n        }\n    }\n\n    /**\n     * @author Lody\n     */\n    /* package */ static class CancelAllNotifications extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"cancelAllNotifications\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = MethodParameterUtils.replaceFirstAppPkg(args);\n            if (VirtualCore.get().isAppInstalled(pkg)) {\n                VNotificationManager.get().cancelAllNotification(pkg, getAppUserId());\n                return 0;\n            }\n            return method.invoke(who, args);\n        }\n    }\n\n    static class AreNotificationsEnabledForPackage extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"areNotificationsEnabledForPackage\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            return VNotificationManager.get().areNotificationsEnabledForPackage(pkg, getAppUserId());\n        }\n    }\n\n    static class SetNotificationsEnabledForPackage extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"setNotificationsEnabledForPackage\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            int enableIndex = ArrayUtils.indexOfFirst(args, Boolean.class);\n            boolean enable = (boolean) args[enableIndex];\n            VNotificationManager.get().setNotificationsEnabledForPackage(pkg, enable, getAppUserId());\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/notification/NotificationManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.notification;\n\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.utils.DeviceUtil;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.NotificationManager;\nimport mirror.android.widget.Toast;\n\n/**\n * @author Lody\n * @see android.app.NotificationManager\n * @see android.widget.Toast\n */\n@Inject(MethodProxies.class)\npublic class NotificationManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {\n\n    public NotificationManagerStub() {\n        super(new MethodInvocationStub<IInterface>(NotificationManager.getService.call()));\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"enqueueToast\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"cancelToast\"));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"removeAutomaticZenRules\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getImportance\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"areNotificationsEnabled\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"setNotificationPolicy\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getNotificationPolicy\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"isNotificationPolicyAccessGrantedForPackage\"));\n        }\n\n        // http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/app/INotificationManager.aidl\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"createNotificationChannelGroups\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getNotificationChannelGroups\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"deleteNotificationChannelGroup\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"createNotificationChannels\"));\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getNotificationChannels\") {\n                @Override\n                public boolean beforeCall(Object who, Method method, Object... args) {\n                    MethodParameterUtils.replaceLastUid(args);\n                    return super.beforeCall(who, method, args);\n                }\n            });\n            addMethodProxy(new StaticMethodProxy(\"getNotificationChannel\") {\n                @Override\n                public boolean beforeCall(Object who, Method method, Object... args) {\n                    MethodParameterUtils.replaceLastUid(args);\n                    int sequence = BuildCompat.isQ() ? 2 : 1;\n                    MethodParameterUtils.replaceSequenceAppPkg(args, sequence);\n                    return super.beforeCall(who, method, args);\n                }\n            });\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"deleteNotificationChannel\"));\n        }\n        if (DeviceUtil.isSamsung()) {\n            addMethodProxy(new ReplaceCallingPkgMethodProxy(\"removeEdgeNotification\"));\n        }\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        NotificationManager.sService.set(getInvocationStub().getProxyInterface());\n        Toast.sService.set(getInvocationStub().getProxyInterface());\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return NotificationManager.getService.call() != getInvocationStub().getProxyInterface();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/os/DeviceIdentifiersPolicyServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.os;\n\nimport android.content.pm.ApplicationInfo;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.os.IDeviceIdentifiersPolicyService;\n\n/**\n * @author weishu\n * @date 2021/8/19.\n */\npublic class DeviceIdentifiersPolicyServiceStub extends BinderInvocationProxy {\n    public DeviceIdentifiersPolicyServiceStub() {\n        super(IDeviceIdentifiersPolicyService.Stub.TYPE, \"device_identifiers\");\n    }\n\n    @Override\n    protected void onBindMethods() {\n\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getSerialForPackage\") {\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                ApplicationInfo info = VClientImpl.get().getCurrentApplicationInfo();\n                if (info != null && info.targetSdkVersion >= 29 && BuildCompat.isQ()) {\n                    return \"unknown\";\n                }\n                return super.call(who, method, args);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/persistent_data_block/PersistentDataBlockServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.persistent_data_block;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport mirror.android.service.persistentdata.IPersistentDataBlockService;\n\n/**\n * @author Lody\n */\npublic class PersistentDataBlockServiceStub extends BinderInvocationProxy {\n\n\tpublic PersistentDataBlockServiceStub() {\n\t\tsuper(IPersistentDataBlockService.Stub.asInterface, \"persistent_data_block\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"write\", -1));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"read\", new byte[0]));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"wipe\", null));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getDataBlockSize\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getMaximumDataBlockSize\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"setOemUnlockEnabled\", 0));\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"getOemUnlockEnabled\", false));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/phonesubinfo/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.phonesubinfo;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.helper.utils.marks.FakeDeviceMark;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"ALL\")\nclass MethodProxies {\n\n    @FakeDeviceMark(\"fake device id\")\n    static class GetDeviceId extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getDeviceId\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return getDeviceInfo().deviceId;\n        }\n    }\n\n    static class GetDeviceIdForSubscriber extends GetDeviceId {\n\n        @Override\n        public String getMethodName() {\n            return \"getDeviceIdForSubscriber\";\n        }\n\n    }\n\n    @FakeDeviceMark(\"fake iccid\")\n    static class GetIccSerialNumber extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getIccSerialNumber\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return getDeviceInfo().iccId;\n        }\n    }\n\n\n    static class getIccSerialNumberForSubscriber extends GetIccSerialNumber {\n        @Override\n        public String getMethodName() {\n            return \"getIccSerialNumberForSubscriber\";\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/phonesubinfo/PhoneSubInfoStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.phonesubinfo;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport mirror.com.android.internal.telephony.IPhoneSubInfo;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic class PhoneSubInfoStub extends BinderInvocationProxy {\n\tpublic PhoneSubInfoStub() {\n\t\tsuper(IPhoneSubInfo.Stub.asInterface, \"iphonesubinfo\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getNaiForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getImeiForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getDeviceSvn\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getDeviceSvnUsingSubId\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getSubscriberId\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getSubscriberIdForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getGroupIdLevel1\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getGroupIdLevel1ForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getLine1Number\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getLine1NumberForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getLine1AlphaTag\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getLine1AlphaTagForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getMsisdn\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getMsisdnForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getVoiceMailNumber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getVoiceMailNumberForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getVoiceMailAlphaTag\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getVoiceMailAlphaTagForSubscriber\"));\n\t}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/LauncherAppsStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.pm;\n\nimport android.content.Context;\nimport android.content.pm.LauncherApps;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\n/**\n * @author weishu\n * @date 2018/7/4.\n */\npublic class LauncherAppsStub extends BinderInvocationProxy {\n\n    public LauncherAppsStub() {\n        super(getInterface(), Context.LAUNCHER_APPS_SERVICE);\n    }\n\n    private static IInterface getInterface() {\n        LauncherApps cm = (LauncherApps) VirtualCore.get().getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);\n        return mirror.android.content.pm.LauncherApps.mService.get(cm);\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        super.inject();\n        LauncherApps cm = (LauncherApps) VirtualCore.get().getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);\n        mirror.android.content.pm.LauncherApps.mService.set(cm, getInvocationStub().getProxyInterface());\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"addOnAppsChangedListener\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getLauncherActivities\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"resolveActivity\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"startActivityAsUser\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"showAppDetailsAsUser\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"isPackageEnabled\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"isActivityEnabled\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getApplicationInfo\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"pinShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"startShortcut\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getShortcutIconResId\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getShortcutIconFd\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"hasShortcutHostPermission\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getShortcutConfigActivities\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getShortcutConfigActivityIntent\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.pm;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageDataObserver;\nimport android.content.pm.IPackageDeleteObserver2;\nimport android.content.pm.IPackageInstallerCallback;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.Signature;\nimport android.graphics.Bitmap;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.Process;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.utils.MethodParameterUtils;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.helper.collection.ArraySet;\nimport com.lody.virtual.helper.compat.ParceledListSliceCompat;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.EncodeUtils;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.server.IPackageInstaller;\nimport com.lody.virtual.server.pm.installer.SessionInfo;\nimport com.lody.virtual.server.pm.installer.SessionParams;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport mirror.android.content.pm.ParceledListSlice;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"unused\")\nclass MethodProxies {\n\n    static class IsPackageAvailable extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"isPackageAvailable\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkgName = (String) args[0];\n            if (isAppPkg(pkgName)) {\n                return true;\n            }\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetInstallerPackageName extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getInstallerPackageName\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return \"com.android.vending\";\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GetPreferredActivities extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPreferredActivities\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceLastAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class GetComponentEnabledSetting extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getComponentEnabledSetting\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            // NOTE: 有4个状态: 0默认 1可用 2禁止 3User Disable\n            ComponentName component = (ComponentName) args[0];\n            if (component != null) {\n                return 1;\n            }\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class RemovePackageFromPreferred extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"removePackageFromPreferred\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n    /**\n     * @author Lody\n     *         <p>\n     *         public ActivityInfo getServiceInfo(ComponentName className, int\n     *         flags, int userId)\n     */\n    static class GetServiceInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getServiceInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName componentName = (ComponentName) args[0];\n            int flags = (int) args[1];\n            int userId = VUserHandle.myUserId();\n            ServiceInfo info = VPackageManager.get().getServiceInfo(componentName, flags, userId);\n            if (info != null) {\n                return info;\n            }\n            info = (ServiceInfo) method.invoke(who, args);\n            if (info == null || !isVisiblePackage(info.applicationInfo)) {\n                return null;\n            }\n            return info;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPackageUid extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageUid\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkgName = (String) args[0];\n            if (pkgName.equals(getHostPkg())) {\n                return method.invoke(who, args);\n            }\n            int uid = VPackageManager.get().getPackageUid(pkgName, 0);\n            return VUserHandle.getAppId(uid);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n    /**\n     * @author Lody\n     *         <p>\n     *         <p>\n     *         public ActivityInfo getActivityInfo(ComponentName className, int\n     *         flags, int userId)\n     */\n    static class GetActivityInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getActivityInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName componentName = (ComponentName) args[0];\n            if (getHostPkg().equals(componentName.getPackageName())) {\n                return method.invoke(who, args);\n            }\n            int userId = VUserHandle.myUserId();\n            int flags = (int) args[1];\n            ActivityInfo info = VPackageManager.get().getActivityInfo(componentName, flags, userId);\n            if (info == null) {\n                info = (ActivityInfo) method.invoke(who, args);\n                if (info == null || !isVisiblePackage(info.applicationInfo)) {\n                    return null;\n                }\n            }\n            return info;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GetPackageUidEtc extends GetPackageUid {\n        @Override\n        public String getMethodName() {\n            return super.getMethodName() + \"Etc\";\n        }\n    }\n\n    static class GetPackageInstaller extends MethodProxy {\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageInstaller\";\n        }\n\n        @Override\n        public Object call(final Object who, Method method, Object... args) throws Throwable {\n            final IInterface installer = (IInterface) method.invoke(who, args);\n            final IPackageInstaller vInstaller = VPackageManager.get().getPackageInstaller();\n            return Proxy.newProxyInstance(installer.getClass().getClassLoader(), installer.getClass().getInterfaces(),\n                    new InvocationHandler() {\n                        @Override\n                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n                            switch (method.getName()) {\n                                case \"createSession\": {\n                                    SessionParams params = SessionParams.create((PackageInstaller.SessionParams) args[0]);\n                                    String installerPackageName = (String) args[1];\n                                    return vInstaller.createSession(params, installerPackageName, VUserHandle.myUserId());\n                                }\n                                case \"updateSessionAppIcon\": {\n                                    int sessionId = (int) args[0];\n                                    Bitmap appIcon = (Bitmap) args[1];\n                                    vInstaller.updateSessionAppIcon(sessionId, appIcon);\n                                    return 0;\n                                }\n                                case \"updateSessionAppLabel\": {\n                                    int sessionId = (int) args[0];\n                                    String appLabel = (String) args[1];\n                                    vInstaller.updateSessionAppLabel(sessionId, appLabel);\n                                    return 0;\n                                }\n                                case \"abandonSession\": {\n                                    vInstaller.abandonSession((Integer) args[0]);\n                                    return 0;\n                                }\n                                case \"openSession\": {\n                                    return vInstaller.openSession((Integer) args[0]);\n                                }\n                                case \"getSessionInfo\": {\n                                    SessionInfo info = vInstaller.getSessionInfo((Integer) args[0]);\n                                    if (info != null) {\n                                        return info.alloc();\n                                    }\n                                    return null;\n                                }\n                                case \"getAllSessions\": {\n                                    return ParceledListSliceCompat.create(\n                                            vInstaller.getAllSessions((Integer) args[0]).getList()\n                                    );\n                                }\n                                case \"getMySessions\": {\n                                    String installerPackageName = (String) args[0];\n                                    int userId = (int) args[1];\n                                    return ParceledListSliceCompat.create(\n                                            vInstaller.getMySessions(installerPackageName, userId).getList()\n                                    );\n                                }\n                                case \"registerCallback\": {\n                                    IPackageInstallerCallback callback = (IPackageInstallerCallback) args[0];\n                                    vInstaller.registerCallback(callback, VUserHandle.myUserId());\n                                    return 0;\n                                }\n                                case \"unregisterCallback\": {\n                                    IPackageInstallerCallback callback = (IPackageInstallerCallback) args[0];\n                                    vInstaller.unregisterCallback(callback);\n                                    return 0;\n                                }\n                                case \"setPermissionsResult\": {\n                                    int sessionId = (int) args[0];\n                                    boolean accepted = (boolean) args[1];\n                                    vInstaller.setPermissionsResult(sessionId, accepted);\n                                    return 0;\n                                }\n                            }\n                            throw new RuntimeException(\"Not support PackageInstaller method : \" + method.getName());\n                        }\n                    });\n        }\n    }\n\n\n    static class FreeStorageAndNotify extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"freeStorageAndNotify\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (args[args.length - 1] instanceof IPackageDataObserver) {\n                IPackageDataObserver observer = (IPackageDataObserver) args[args.length - 1];\n                observer.onRemoveCompleted(null, true);\n            }\n            return 0;\n        }\n    }\n\n\n    static class GetPackageGids extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageGids\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n\n    }\n\n\n    static class RevokeRuntimePermission extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"revokeRuntimePermission\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class ClearPackagePreferredActivities extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"clearPackagePreferredActivities\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class ResolveContentProvider extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"resolveContentProvider\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String name = (String) args[0];\n            int flags = (int) args[1];\n            int userId = VUserHandle.myUserId();\n            ProviderInfo info = VPackageManager.get().resolveContentProvider(name, flags, userId);\n            if (info == null) {\n                info = (ProviderInfo) method.invoke(who, args);\n                if (info != null && isVisiblePackage(info.applicationInfo)) {\n                    return info;\n                }\n            }\n            return info;\n        }\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    static class QueryIntentServices extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"queryIntentServices\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method);\n            int userId = VUserHandle.myUserId();\n            List<ResolveInfo> appResult = VPackageManager.get().queryIntentServices((Intent) args[0],\n                    (String) args[1], (Integer) args[2], userId);\n            Object _hostResult = method.invoke(who, args);\n            if (_hostResult != null) {\n                List<ResolveInfo> hostResult = slice ? ParceledListSlice.getList.call(_hostResult)\n                        : (List) _hostResult;\n                if (hostResult != null) {\n                    Iterator<ResolveInfo> iterator = hostResult.iterator();\n                    while (iterator.hasNext()) {\n                        ResolveInfo info = iterator.next();\n                        if (info == null || info.serviceInfo == null || !isVisiblePackage(info.serviceInfo.applicationInfo)) {\n                            iterator.remove();\n                        }\n                    }\n                    appResult.addAll(hostResult);\n                }\n            }\n            if (slice) {\n                return ParceledListSliceCompat.create(appResult);\n            }\n            return appResult;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPermissions extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPermissions\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return method.invoke(who, args);\n        }\n    }\n\n    static class IsPackageForzen extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"isPackageForzen\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return false;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPackageGidsEtc extends GetPackageGids {\n\n        @Override\n        public String getMethodName() {\n            return super.getMethodName() + \"Etc\";\n        }\n\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    static class QueryIntentActivities extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"queryIntentActivities\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method);\n            int userId = VUserHandle.myUserId();\n            List<ResolveInfo> appResult = VPackageManager.get().queryIntentActivities((Intent) args[0],\n                    (String) args[1], (Integer) args[2], userId);\n            Object _hostResult = method.invoke(who, args);\n            if (_hostResult != null) {\n                List<ResolveInfo> hostResult = slice ? ParceledListSlice.getList.call(_hostResult)\n                        : (List) _hostResult;\n                if (hostResult != null) {\n                    Iterator<ResolveInfo> iterator = hostResult.iterator();\n                    while (iterator.hasNext()) {\n                        ResolveInfo info = iterator.next();\n                        if (info == null || info.activityInfo == null || !isVisiblePackage(info.activityInfo.applicationInfo)) {\n                            iterator.remove();\n                        }\n                    }\n                    appResult.addAll(hostResult);\n                }\n            }\n            if (slice) {\n                return ParceledListSliceCompat.create(appResult);\n            }\n            return appResult;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class ResolveService extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"resolveService\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            Intent intent = (Intent) args[0];\n            String resolvedType = (String) args[1];\n            int flags = (int) args[2];\n            int userId = VUserHandle.myUserId();\n            ResolveInfo resolveInfo = VPackageManager.get().resolveService(intent, resolvedType, flags, userId);\n            if (resolveInfo == null) {\n                resolveInfo = (ResolveInfo) method.invoke(who, args);\n            }\n            return resolveInfo;\n        }\n    }\n\n\n    static class ClearPackagePersistentPreferredActivities extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"clearPackagePersistentPreferredActivities\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n    static class GetPermissionGroupInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPermissionGroupInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String name = (String) args[0];\n            int flags = (int) args[1];\n            PermissionGroupInfo info = VPackageManager.get().getPermissionGroupInfo(name, flags);\n            if (info != null) {\n                return info;\n            }\n            return super.call(who, method, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static final class GetPackageInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPackageInfo\";\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            return args != null && args[0] != null;\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            int flags = (int) args[1];\n            int userId = VUserHandle.myUserId();\n            PackageInfo packageInfo = VPackageManager.get().getPackageInfo(pkg, flags, userId);\n            if (packageInfo != null) {\n                return packageInfo;\n            }\n            packageInfo = (PackageInfo) method.invoke(who, args);\n            if (packageInfo != null) {\n                if (isVisiblePackage(packageInfo.applicationInfo)) {\n                    return packageInfo;\n                }\n            }\n            return null;\n        }\n\n    }\n\n\n    static class DeleteApplicationCacheFiles extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"deleteApplicationCacheFiles\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            // TODO\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class SetApplicationBlockedSettingAsUser extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"setApplicationBlockedSettingAsUser\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetApplicationEnabledSetting extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getApplicationEnabledSetting\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n    static class AddPackageToPreferred extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"addPackageToPreferred\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return 0;\n        }\n    }\n\n    static class CheckPermission extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"checkPermission\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String permName = (String) args[0];\n            String pkgName = (String) args[1];\n            int userId = VUserHandle.myUserId();\n            return VPackageManager.get().checkPermission(permName, pkgName, userId);\n        }\n\n        @Override\n        public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {\n            return super.afterCall(who, method, args, result);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetPackagesForUid extends MethodProxy {\n\n\n        @Override\n        public String getMethodName() {\n            return \"getPackagesForUid\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int uid = (int) args[0];\n            int callingUid = Binder.getCallingUid();\n            if (uid == VirtualCore.get().myUid()) {\n                uid = getBaseVUid();\n            }\n            String[] callingPkgs = VPackageManager.get().getPackagesForUid(callingUid);\n            String[] targetPkgs = VPackageManager.get().getPackagesForUid(uid);\n            String[] selfPkgs = VPackageManager.get().getPackagesForUid(Process.myUid());\n\n            Set<String> pkgList = new ArraySet<>(2);\n            if (callingPkgs != null && callingPkgs.length > 0) {\n                pkgList.addAll(Arrays.asList(callingPkgs));\n            }\n            if (targetPkgs != null && targetPkgs.length > 0) {\n                pkgList.addAll(Arrays.asList(targetPkgs));\n            }\n            if (selfPkgs != null && selfPkgs.length > 0) {\n                pkgList.addAll(Arrays.asList(selfPkgs));\n            }\n            return pkgList.toArray(new String[pkgList.size()]);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    static class QueryContentProviders extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"queryContentProviders\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String processName = (String) args[0];\n            int uid = (int) args[1];\n            int flags = (int) args[2];\n            List<ProviderInfo> infos = VPackageManager.get().queryContentProviders(processName, uid, flags);\n            if (ParceledListSliceCompat.isReturnParceledListSlice(method)) {\n                return ParceledListSliceCompat.create(infos);\n            }\n            return infos;\n        }\n\n    }\n\n    static class SetApplicationEnabledSetting extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"setApplicationEnabledSetting\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    @SuppressLint(\"PackageManagerGetSignatures\")\n    static class CheckSignatures extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"checkSignatures\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n\n            if (args.length == 2 && args[0] instanceof String && args[1] instanceof String) {\n\n                PackageManager pm = VirtualCore.getPM();\n\n                String pkgNameOne = (String) args[0], pkgNameTwo = (String) args[1];\n                try {\n                    PackageInfo pkgOne = pm.getPackageInfo(pkgNameOne, PackageManager.GET_SIGNATURES);\n                    PackageInfo pkgTwo = pm.getPackageInfo(pkgNameTwo, PackageManager.GET_SIGNATURES);\n\n                    Signature[] one = pkgOne.signatures;\n                    Signature[] two = pkgTwo.signatures;\n\n                    if (ArrayUtils.isEmpty(one)) {\n                        if (!ArrayUtils.isEmpty(two)) {\n                            return PackageManager.SIGNATURE_FIRST_NOT_SIGNED;\n                        } else {\n                            return PackageManager.SIGNATURE_NEITHER_SIGNED;\n                        }\n                    } else {\n                        if (ArrayUtils.isEmpty(two)) {\n                            return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;\n                        } else {\n                            if (Arrays.equals(one, two)) {\n                                return PackageManager.SIGNATURE_MATCH;\n                            } else {\n                                return PackageManager.SIGNATURE_NO_MATCH;\n                            }\n                        }\n                    }\n                } catch (Throwable e) {\n                    // Ignore\n                }\n            }\n\n            return method.invoke(who, args);\n        }\n    }\n\n    static class checkUidSignatures extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"checkUidSignatures\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int uid1 = (int) args[0];\n            int uid2 = (int) args[1];\n            // TODO: verify the signatures by uid.\n            return PackageManager.SIGNATURE_MATCH;\n        }\n    }\n\n    static class getNameForUid extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getNameForUid\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int uid = (int) args[0];\n            return VPackageManager.get().getNameForUid(uid);\n        }\n    }\n\n\n    static class DeletePackage extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"deletePackage\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkgName = (String) args[0];\n            try {\n                VirtualCore.get().uninstallPackage(pkgName);\n                IPackageDeleteObserver2 observer = (IPackageDeleteObserver2) args[1];\n                if (observer != null) {\n                    observer.onPackageDeleted(pkgName, 0, \"done.\");\n                }\n            } catch (Throwable e) {\n                // Ignore\n            }\n            return 0;\n        }\n\n    }\n\n\n    static class ActivitySupportsIntent extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"activitySupportsIntent\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName component = (ComponentName) args[0];\n            Intent intent = (Intent) args[1];\n            String resolvedType = (String) args[2];\n            return VPackageManager.get().activitySupportsIntent(component, intent, resolvedType);\n        }\n    }\n\n\n    static class ResolveIntent extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"resolveIntent\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            Intent intent = (Intent) args[0];\n            String resolvedType = (String) args[1];\n            int flags = (int) args[2];\n            int userId = VUserHandle.myUserId();\n            ResolveInfo resolveInfo = VPackageManager.get().resolveIntent(intent, resolvedType, flags, userId);\n            if (resolveInfo == null) {\n                resolveInfo = (ResolveInfo) method.invoke(who, args);\n            }\n            return resolveInfo;\n        }\n    }\n\n\n    static class GetApplicationInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getApplicationInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            String pkg = (String) args[0];\n            int flags = (int) args[1];\n            if (getHostPkg().equals(pkg)) {\n                return method.invoke(who, args);\n            }\n            int userId = VUserHandle.myUserId();\n            ApplicationInfo info = VPackageManager.get().getApplicationInfo(pkg, flags, userId);\n            if (info != null) {\n                return info;\n            }\n            info = (ApplicationInfo) method.invoke(who, args);\n            if (info == null || !isVisiblePackage(info)) {\n                return null;\n            }\n            return info;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetProviderInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getProviderInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName componentName = (ComponentName) args[0];\n            int flags = (int) args[1];\n            if (getHostPkg().equals(componentName.getPackageName())) {\n                return method.invoke(who, args);\n            }\n            int userId = VUserHandle.myUserId();\n            ProviderInfo info = VPackageManager.get().getProviderInfo(componentName, flags, userId);\n            if (info == null) {\n                info = (ProviderInfo) method.invoke(who, args);\n                if (info == null || !isVisiblePackage(info.applicationInfo)) {\n                    return null;\n                }\n            }\n            return info;\n        }\n\n    }\n\n    static class SetComponentEnabledSetting extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            // return \"setComponentEnabledSetting\";\n            // anti-virus, fuck ESET-NOD32: a variant of Android/AdDisplay.AdLock.AL potentially unwanted\n            return EncodeUtils.decode(\"c2V0Q29tcG9uZW50RW5hYmxlZFNldHRpbmc=\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return 0;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n    static class GetInstalledApplications extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getInstalledApplications\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n\n            int flags = (Integer) args[0];\n            int userId = VUserHandle.myUserId();\n            List<ApplicationInfo> appInfos = VPackageManager.get().getInstalledApplications(flags, userId);\n            if (ParceledListSliceCompat.isReturnParceledListSlice(method)) {\n                return ParceledListSliceCompat.create(appInfos);\n            }\n            return appInfos;\n        }\n    }\n\n    @SuppressWarnings({\"unchecked\", \"WrongConstant\"})\n    static class GetInstalledPackages extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getInstalledPackages\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int flags = (int) args[0];\n            int userId = VUserHandle.myUserId();\n            List<PackageInfo> packageInfos;\n            if (isAppProcess()) {\n                packageInfos = new ArrayList<>(VirtualCore.get().getInstalledAppCount());\n            } else {\n                packageInfos = VirtualCore.get().getUnHookPackageManager().getInstalledPackages(flags);\n            }\n            packageInfos.addAll(VPackageManager.get().getInstalledPackages(flags, userId));\n            if (ParceledListSliceCompat.isReturnParceledListSlice(method)) {\n                return ParceledListSliceCompat.create(packageInfos);\n            } else {\n                return packageInfos;\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    static class QueryIntentReceivers extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"queryIntentReceivers\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method);\n            int userId = VUserHandle.myUserId();\n            List<ResolveInfo> appResult = VPackageManager.get().queryIntentReceivers((Intent) args[0], (String) args[1],\n                    (Integer) args[2], userId);\n            Object _hostResult = method.invoke(who, args);\n            List<ResolveInfo> hostResult = slice ? ParceledListSlice.getList.call(_hostResult)\n                    : (List) _hostResult;\n            if (hostResult != null) {\n                Iterator<ResolveInfo> iterator = hostResult.iterator();\n                while (iterator.hasNext()) {\n                    ResolveInfo info = iterator.next();\n                    if (info == null || info.activityInfo == null || !isVisiblePackage(info.activityInfo.applicationInfo)) {\n                        iterator.remove();\n                    }\n                }\n                appResult.addAll(hostResult);\n            }\n            if (slice) {\n                return ParceledListSliceCompat.create(appResult);\n            }\n            return appResult;\n        }\n    }\n\n\n    static class GetReceiverInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getReceiverInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName componentName = (ComponentName) args[0];\n            if (getHostPkg().equals(componentName.getPackageName())) {\n                return method.invoke(who, args);\n            }\n            int flags = (int) args[1];\n            ActivityInfo info = VPackageManager.get().getReceiverInfo(componentName, flags, 0);\n            if (info == null) {\n                info = (ActivityInfo) method.invoke(who, args);\n                if (info == null || !isVisiblePackage(info.applicationInfo)) {\n                    return null;\n                }\n            }\n            return info;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\n    static class GetPermissionFlags extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getPermissionFlags\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            // TODO\n            return method.invoke(who, args);\n        }\n\n    }\n\n\n    static class SetPackageStoppedState extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"setPackageStoppedState\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    @SuppressWarnings(\"unchecked\")\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    static class QueryIntentContentProviders extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"queryIntentContentProviders\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method);\n            int userId = VUserHandle.myUserId();\n            List<ResolveInfo> appResult = VPackageManager.get().queryIntentContentProviders((Intent) args[0], (String) args[1],\n                    (Integer) args[2], userId);\n            Object _hostResult = method.invoke(who, args);\n            List<ResolveInfo> hostResult = slice ? ParceledListSlice.getList.call(_hostResult)\n                    : (List) _hostResult;\n            if (hostResult != null) {\n                Iterator<ResolveInfo> iterator = hostResult.iterator();\n                while (iterator.hasNext()) {\n                    ResolveInfo info = iterator.next();\n                    if (info == null || info.providerInfo == null || !isVisiblePackage(info.providerInfo.applicationInfo)) {\n                        iterator.remove();\n                    }\n                }\n                appResult.addAll(hostResult);\n            }\n            if (ParceledListSliceCompat.isReturnParceledListSlice(method)) {\n                return ParceledListSliceCompat.create(appResult);\n            }\n            return appResult;\n        }\n\n        @Override\n        public boolean isEnable() {\n            return isAppProcess();\n        }\n    }\n\n\n    static class GetApplicationBlockedSettingAsUser extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getApplicationBlockedSettingAsUser\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            MethodParameterUtils.replaceFirstAppPkg(args);\n            return method.invoke(who, args);\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/PackageManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.pm;\n\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationStub;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport mirror.android.app.ActivityThread;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic final class PackageManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {\n\n    public PackageManagerStub() {\n        super(new MethodInvocationStub<>(ActivityThread.sPackageManager.get()));\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ResultStaticMethodProxy(\"addPermissionAsync\", true));\n        addMethodProxy(new ResultStaticMethodProxy(\"addPermission\", true));\n        addMethodProxy(new ResultStaticMethodProxy(\"performDexOpt\", true));\n        addMethodProxy(new ResultStaticMethodProxy(\"performDexOptIfNeeded\", false));\n        addMethodProxy(new ResultStaticMethodProxy(\"performDexOptSecondary\", true));\n        addMethodProxy(new ResultStaticMethodProxy(\"addOnPermissionsChangeListener\", 0));\n        addMethodProxy(new ResultStaticMethodProxy(\"removeOnPermissionsChangeListener\", 0));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            addMethodProxy(new ResultStaticMethodProxy(\"checkPackageStartable\", 0));\n        }\n        if (BuildCompat.isOreo()) {\n            addMethodProxy(new ResultStaticMethodProxy(\"notifyDexLoad\", 0));\n            addMethodProxy(new ResultStaticMethodProxy(\"notifyPackageUse\", 0));\n            addMethodProxy(new ResultStaticMethodProxy(\"setInstantAppCookie\", false));\n            addMethodProxy(new ResultStaticMethodProxy(\"isInstantApp\", false));\n        }\n\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        final IInterface hookedPM = getInvocationStub().getProxyInterface();\n        ActivityThread.sPackageManager.set(hookedPM);\n        BinderInvocationStub pmHookBinder = new BinderInvocationStub(getInvocationStub().getBaseInterface());\n        pmHookBinder.copyMethodProxies(getInvocationStub());\n        pmHookBinder.replaceService(\"package\");\n    }\n\n    @Override\n    public boolean isEnvBad() {\n        return getInvocationStub().getProxyInterface() != ActivityThread.sPackageManager.get();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/power/PowerManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.power;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceSequencePkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport mirror.android.os.IPowerManager;\n\n/**\n * @author Lody\n */\npublic class PowerManagerStub extends BinderInvocationProxy {\n\n\tpublic PowerManagerStub() {\n\t\tsuper(IPowerManager.Stub.asInterface, Context.POWER_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceSequencePkgMethodProxy(\"acquireWakeLock\", 2) {\n\t\t\t@Override\n\t\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\t\ttry {\n\t\t\t\t\treturn super.call(who, method, args);\n\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\treturn onHandleError(e);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"acquireWakeLockWithUid\") {\n\n\t\t\t@Override\n\t\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable {\n\t\t\t\ttry {\n\t\t\t\t\treturn super.call(who, method, args);\n\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\treturn onHandleError(e);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\taddMethodProxy(new ResultStaticMethodProxy(\"updateWakeLockWorkSource\", 0));\n\t}\n\n\tprivate Object onHandleError(InvocationTargetException e) throws Throwable {\n\t\tif (e.getCause() instanceof SecurityException) {\n\t\t\treturn 0;\n\t\t}\n\t\tthrow e.getCause();\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/restriction/RestrictionStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.restriction;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport mirror.android.content.IRestrictionsManager;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\npublic class RestrictionStub extends BinderInvocationProxy {\n\tpublic RestrictionStub() {\n\t\tsuper(IRestrictionsManager.Stub.asInterface, Context.RESTRICTIONS_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getApplicationRestrictions\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"notifyPermissionResponse\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"requestPermission\"));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/search/SearchManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.search;\n\nimport android.annotation.TargetApi;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.ActivityInfo;\nimport android.os.Build;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\n\nimport java.lang.reflect.Method;\n\nimport mirror.android.app.ISearchManager;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class SearchManagerStub extends BinderInvocationProxy {\n\n    public SearchManagerStub() {\n        super(ISearchManager.Stub.asInterface, Context.SEARCH_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new StaticMethodProxy(\"launchLegacyAssist\"));\n        addMethodProxy(new GetSearchableInfo());\n    }\n\n     private static class GetSearchableInfo extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"getSearchableInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            ComponentName component = (ComponentName) args[0];\n            if (component != null) {\n                ActivityInfo activityInfo = VirtualCore.getPM().getActivityInfo(component, 0);\n                if (activityInfo != null) {\n                    return null;\n                }\n            }\n            return method.invoke(who, args);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/shortcut/ShortcutServiceStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.shortcut;\n\nimport android.annotation.TargetApi;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ShortcutInfo;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.Icon;\nimport android.os.Build;\nimport android.os.PersistableBundle;\n\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.helper.compat.ParceledListSliceCompat;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport mirror.android.content.pm.IShortcutService;\nimport mirror.android.content.pm.ParceledListSlice;\n\n/**\n * @author Lody\n */\npublic class ShortcutServiceStub extends BinderInvocationProxy {\n\n\n    public ShortcutServiceStub() {\n        super(IShortcutService.Stub.asInterface, \"shortcut\");\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        super.inject();\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getManifestShortcuts\"));\n        // TODO: 18/3/3 Support dynamic shortcut ?\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getDynamicShortcuts\"));\n        addMethodProxy(new ReplacePkgAndShortcutListMethodProxy(\"setDynamicShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"addDynamicShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"createShortcutResultIntent\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"disableShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"enableShortcuts\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getRemainingCallCount\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getRateLimitResetTime\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getIconMaxDimensions\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getMaxShortcutCountPerActivity\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"reportShortcutUsed\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"onApplicationActive\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"removeAllDynamicShortcuts\"));\n\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getPinnedShortcuts\"));\n        addMethodProxy(new ReplacePkgAndShortcutMethodProxy(\"requestPinShortcut\"));\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    private static void replaceShortcutInfo(ShortcutInfo shortcutInfo, String hostPackage, PackageManager pm) {\n        if (shortcutInfo == null) {\n            return;\n        }\n\n        mirror.android.content.pm.ShortcutInfo.mPackageName.set(shortcutInfo, hostPackage);\n        try {\n            Drawable applicationIcon = pm.getApplicationIcon(hostPackage);\n            Icon icon = Icon.createWithBitmap(((BitmapDrawable) applicationIcon).getBitmap());\n            mirror.android.content.pm.ShortcutInfo.mIcon.set(shortcutInfo, icon);\n        } catch (Throwable ignored) {\n        }\n\n        Intent[] intents = mirror.android.content.pm.ShortcutInfo.mIntents.get(shortcutInfo);\n\n        if (intents != null) {\n            int length = intents.length;\n            Intent[] swap = new Intent[length];\n\n            PersistableBundle[] persistableBundles = mirror.android.content.pm.ShortcutInfo.mIntentPersistableExtrases.get(shortcutInfo);\n            if (persistableBundles == null) {\n                persistableBundles = new PersistableBundle[length];\n            }\n\n            for (int i = 0; i < length; i++) {\n                Intent intent = intents[i];\n                PersistableBundle persistableBundle = persistableBundles[i];\n                if (persistableBundle == null) {\n                    persistableBundle = new PersistableBundle();\n                }\n\n                Intent shortcutIntent = new Intent();\n                shortcutIntent.setClassName(hostPackage, Constants.SHORTCUT_PROXY_ACTIVITY_NAME);\n                shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);\n\n                persistableBundle.putString(\"_VA_|_uri_\", intent.toUri(0));\n                persistableBundle.putInt(\"_VA_|_user_id_\", 0);\n                swap[i] = shortcutIntent;\n            }\n\n            System.arraycopy(swap, 0, intents, 0, length);\n            mirror.android.content.pm.ShortcutInfo.mIntentPersistableExtrases.set(shortcutInfo, persistableBundles);\n        }\n    }\n\n    private static class ReplacePkgAndShortcutListMethodProxy extends ReplaceCallingPkgMethodProxy {\n        ReplacePkgAndShortcutListMethodProxy(String name) {\n            super(name);\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n\n            List<ShortcutInfo> shortcutList = findFirstShortcutList(args);\n            if (shortcutList != null) {\n                String hostPkg = getHostPkg();\n                for (ShortcutInfo shortcutInfo : shortcutList) {\n                    replaceShortcutInfo(shortcutInfo, hostPkg, getPM());\n                }\n            }\n\n            return super.beforeCall(who, method, args);\n        }\n\n        @TargetApi(Build.VERSION_CODES.N_MR1)\n        private List<ShortcutInfo> findFirstShortcutList(Object... args) {\n            if (args == null) {\n                return null;\n            }\n            for (Object arg : args) {\n                if (arg.getClass().isAssignableFrom(ParceledListSlice.TYPE)) {\n                    return ParceledListSliceCompat.getList(arg);\n                }\n            }\n            return null;\n        }\n    }\n\n    private static class ReplacePkgAndShortcutMethodProxy extends ReplaceCallingPkgMethodProxy {\n\n        ReplacePkgAndShortcutMethodProxy(String name) {\n            super(name);\n        }\n\n        @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            ShortcutInfo shortcutInfo = findFirstShortcutInfo(args);\n            replaceShortcutInfo(shortcutInfo, getHostPkg(), getPM());\n\n            return super.beforeCall(who, method, args);\n        }\n\n        @TargetApi(Build.VERSION_CODES.N_MR1)\n        private ShortcutInfo findFirstShortcutInfo(Object[] args) {\n            if (args == null) {\n                return null;\n            }\n            for (Object arg : args) {\n                if (arg.getClass() == mirror.android.content.pm.ShortcutInfo.TYPE) {\n                    return (ShortcutInfo) arg;\n                }\n            }\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/telephony/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.telephony;\n\nimport android.os.Bundle;\nimport android.telephony.CellIdentityCdma;\nimport android.telephony.CellIdentityGsm;\nimport android.telephony.CellInfo;\nimport android.telephony.CellInfoCdma;\nimport android.telephony.CellInfoGsm;\nimport android.telephony.CellSignalStrengthCdma;\nimport android.telephony.CellSignalStrengthGsm;\nimport android.telephony.NeighboringCellInfo;\nimport android.telephony.cdma.CdmaCellLocation;\nimport android.telephony.gsm.GsmCellLocation;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.helper.utils.marks.FakeDeviceMark;\nimport com.lody.virtual.helper.utils.marks.FakeLocMark;\nimport com.lody.virtual.remote.vloc.VCell;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author Lody\n */\n@SuppressWarnings(\"ALL\")\nclass MethodProxies {\n\n    @FakeDeviceMark(\"fake device id.\")\n    static class GetDeviceId extends StaticMethodProxy {\n\n        public GetDeviceId() {\n            super(\"getDeviceId\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            return getDeviceInfo().deviceId;\n        }\n    }\n\n    @FakeLocMark(\"cell location\")\n    static class GetCellLocation extends ReplaceCallingPkgMethodProxy {\n\n        public GetCellLocation() {\n            super(\"getCellLocation\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                VCell cell = VirtualLocationManager.get().getCell(getAppUserId(), getAppPkg());\n                if (cell != null) {\n                    return getCellLocationInternal(cell);\n                }\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    static class getAllCellInfoUsingSubId extends ReplaceCallingPkgMethodProxy {\n\n        public getAllCellInfoUsingSubId() {\n            super(\"getAllCellInfoUsingSubId\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                return null;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    @FakeLocMark(\"cell location\")\n    static class GetAllCellInfo extends ReplaceCallingPkgMethodProxy {\n\n        public GetAllCellInfo() {\n            super(\"getAllCellInfo\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                List<VCell> cells = VirtualLocationManager.get().getAllCell(getAppUserId(), getAppPkg());\n                if (cells != null) {\n                    List<CellInfo> result = new ArrayList<CellInfo>();\n                    for (VCell cell : cells) {\n                        result.add(createCellInfo(cell));\n                    }\n                    return result;\n                }\n\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    @FakeLocMark(\"neb cell location\")\n    static class GetNeighboringCellInfo extends ReplaceCallingPkgMethodProxy {\n\n        public GetNeighboringCellInfo() {\n            super(\"getNeighboringCellInfo\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (isFakeLocationEnable()) {\n                List<VCell> cells = VirtualLocationManager.get().getNeighboringCell(getAppUserId(), getAppPkg());\n                if (cells != null) {\n                    List<NeighboringCellInfo> infos = new ArrayList<>();\n                    for (VCell cell : cells) {\n                        NeighboringCellInfo info = new NeighboringCellInfo();\n                        mirror.android.telephony.NeighboringCellInfo.mLac.set(info, cell.lac);\n                        mirror.android.telephony.NeighboringCellInfo.mCid.set(info, cell.cid);\n                        mirror.android.telephony.NeighboringCellInfo.mRssi.set(info, 6);\n                        infos.add(info);\n                    }\n                    return infos;\n                }\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    private static Bundle getCellLocationInternal(VCell cell) {\n        if (cell != null) {\n            Bundle cellData = new Bundle();\n            if (cell.type == 2) {\n                try {\n                    CdmaCellLocation cellLoc = new CdmaCellLocation();\n                    cellLoc.setCellLocationData(cell.baseStationId, Integer.MAX_VALUE, Integer.MAX_VALUE, cell.systemId, cell.networkId);\n                    cellLoc.fillInNotifierBundle(cellData);\n                } catch (Throwable e) {\n                    cellData.putInt(\"baseStationId\", cell.baseStationId);\n                    cellData.putInt(\"baseStationLatitude\", Integer.MAX_VALUE);\n                    cellData.putInt(\"baseStationLongitude\", Integer.MAX_VALUE);\n                    cellData.putInt(\"systemId\", cell.systemId);\n                    cellData.putInt(\"networkId\", cell.networkId);\n                }\n            } else {\n                try {\n                    GsmCellLocation cellLoc = new GsmCellLocation();\n                    cellLoc.setLacAndCid(cell.lac, cell.cid);\n                    cellLoc.fillInNotifierBundle(cellData);\n                } catch (Throwable e) {\n                    cellData.putInt(\"lac\", cell.lac);\n                    cellData.putInt(\"cid\", cell.cid);\n                    cellData.putInt(\"psc\", cell.psc);\n                }\n            }\n            return cellData;\n        }\n        return null;\n    }\n\n\n    private static CellInfo createCellInfo(VCell cell) {\n        if (cell.type == 2) { // CDMA\n            CellInfoCdma cdma = mirror.android.telephony.CellInfoCdma.ctor.newInstance();\n            CellIdentityCdma identityCdma = mirror.android.telephony.CellInfoCdma.mCellIdentityCdma.get(cdma);\n            CellSignalStrengthCdma strengthCdma = mirror.android.telephony.CellInfoCdma.mCellSignalStrengthCdma.get(cdma);\n            mirror.android.telephony.CellIdentityCdma.mNetworkId.set(identityCdma, cell.networkId);\n            mirror.android.telephony.CellIdentityCdma.mSystemId.set(identityCdma, cell.systemId);\n            mirror.android.telephony.CellIdentityCdma.mBasestationId.set(identityCdma, cell.baseStationId);\n            mirror.android.telephony.CellSignalStrengthCdma.mCdmaDbm.set(strengthCdma, -74);\n            mirror.android.telephony.CellSignalStrengthCdma.mCdmaEcio.set(strengthCdma, -91);\n            mirror.android.telephony.CellSignalStrengthCdma.mEvdoDbm.set(strengthCdma, -64);\n            mirror.android.telephony.CellSignalStrengthCdma.mEvdoSnr.set(strengthCdma, 7);\n            return cdma;\n        } else { // GSM\n            CellInfoGsm gsm = mirror.android.telephony.CellInfoGsm.ctor.newInstance();\n            CellIdentityGsm identityGsm = mirror.android.telephony.CellInfoGsm.mCellIdentityGsm.get(gsm);\n            CellSignalStrengthGsm strengthGsm = mirror.android.telephony.CellInfoGsm.mCellSignalStrengthGsm.get(gsm);\n            mirror.android.telephony.CellIdentityGsm.mMcc.set(identityGsm, cell.mcc);\n            mirror.android.telephony.CellIdentityGsm.mMnc.set(identityGsm, cell.mnc);\n            mirror.android.telephony.CellIdentityGsm.mLac.set(identityGsm, cell.lac);\n            mirror.android.telephony.CellIdentityGsm.mCid.set(identityGsm, cell.cid);\n            mirror.android.telephony.CellSignalStrengthGsm.mSignalStrength.set(strengthGsm, 20);\n            mirror.android.telephony.CellSignalStrengthGsm.mBitErrorRate.set(strengthGsm, 0);\n            return gsm;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/telephony/TelephonyRegistryStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.telephony;\n\nimport android.telephony.PhoneStateListener;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceSequencePkgMethodProxy;\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.lang.reflect.Method;\n\nimport mirror.com.android.internal.telephony.ITelephonyRegistry;\n\npublic class TelephonyRegistryStub extends BinderInvocationProxy {\n\n\tpublic TelephonyRegistryStub() {\n\t\tsuper(ITelephonyRegistry.Stub.asInterface, \"telephony.registry\");\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"listen\"));\n\t\taddMethodProxy(new ReplaceSequencePkgMethodProxy(\"listenForSubscriber\", 1) {\n\t\t\t@Override\n\t\t\tpublic boolean beforeCall(Object who, Method method, Object... args) {\n\t\t\t\tif (android.os.Build.VERSION.SDK_INT >= 17) {\n\t\t\t\t\tif (isFakeLocationEnable()) {\n\t\t\t\t\t\tfor (int i = args.length - 1; i > 0; i--) {\n\t\t\t\t\t\t\tif (args[i] instanceof Integer) {\n\t\t\t\t\t\t\t\tint events = (Integer) args[i];\n\t\t\t\t\t\t\t\tevents ^= PhoneStateListener.LISTEN_CELL_INFO;\n\t\t\t\t\t\t\t\tevents ^= PhoneStateListener.LISTEN_CELL_LOCATION;\n\t\t\t\t\t\t\t\targs[i] = events;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn super.beforeCall(who, method, args);\n\t\t\t}\n\t\t});\n\n\t\tif (BuildCompat.isS()) {\n\t\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"listenWithEventList\"));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/telephony/TelephonyStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.telephony;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport java.lang.reflect.Method;\n\nimport mirror.com.android.internal.telephony.ITelephony;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic class TelephonyStub extends BinderInvocationProxy {\n\n\tpublic TelephonyStub() {\n\t\tsuper(ITelephony.Stub.asInterface, Context.TELEPHONY_SERVICE);\n\t}\n\n\t@Override\n\tprotected void onBindMethods() {\n\t\tsuper.onBindMethods();\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"isOffhook\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getLine1NumberForDisplay\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"isOffhookForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"isRingingForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"call\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"isRinging\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"isIdle\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"isIdleForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"isRadioOn\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"isRadioOnForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"isSimPinEnabled\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getCdmaEriIconIndex\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getCdmaEriIconIndexForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getCdmaEriIconMode\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getCdmaEriIconModeForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getCdmaEriText\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getCdmaEriTextForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getNetworkTypeForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getDataNetworkType\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getDataNetworkTypeForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getVoiceNetworkTypeForSubscriber\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getLteOnCdmaMode\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getLteOnCdmaModeForSubscriber\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getCalculatedPreferredNetworkType\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getPcscfAddress\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getLine1AlphaTagForDisplay\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getMergedSubscriberIds\"));\n\t\taddMethodProxy(new ReplaceLastPkgMethodProxy(\"getRadioAccessFamily\"));\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"isVideoCallingEnabled\"));\n\n\t\taddMethodProxy(new ReplaceCallingPkgMethodProxy(\"getDeviceIdWithFeature\") {\n\t\t\t@Override\n\t\t\tpublic Object call(Object who, Method method, Object... args) throws Throwable{\n\t\t\t\ttry {\n\t\t\t\t\treturn super.call(who, method, args);\n\t\t\t\t} catch (SecurityException e) {\n\t\t\t\t\tApplicationInfo ai = VClientImpl.get().getCurrentApplicationInfo();\n\t\t\t\t\tif (ai.targetSdkVersion >= 29) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\t\t\t\t\t\tContext context = VirtualCore.get().getContext();\n\t\t\t\t\t\tif (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE)\n\t\t\t\t\t\t\t\t!= PackageManager.PERMISSION_GRANTED) {\n\t\t\t\t\t\t\t// 不排除不检查权限直接使用 try-catch 判断的情况\n\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/usage/UsageStatsManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.usage;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\n\nimport mirror.android.app.IUsageStatsManager;\n\n/**\n * Created by caokai on 2017/9/8.\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)\npublic class UsageStatsManagerStub extends BinderInvocationProxy {\n\n    public UsageStatsManagerStub() {\n        super(IUsageStatsManager.Stub.asInterface, Context.USAGE_STATS_SERVICE);\n    }\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"queryUsageStats\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"queryConfigurations\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"queryEvents\"));\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/user/UserManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.user;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.ResultStaticMethodProxy;\n\nimport java.util.Collections;\n\nimport mirror.android.content.pm.UserInfo;\nimport mirror.android.os.IUserManager;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class UserManagerStub extends BinderInvocationProxy {\n\n    public UserManagerStub() {\n        super(IUserManager.Stub.asInterface, Context.USER_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"setApplicationRestrictions\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getApplicationRestrictions\"));\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getApplicationRestrictionsForUser\"));\n        addMethodProxy(new ResultStaticMethodProxy(\"getProfileParent\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"getUserIcon\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"getUserInfo\", UserInfo.ctor.newInstance(0, \"Admin\", UserInfo.FLAG_PRIMARY.get())));\n        addMethodProxy(new ResultStaticMethodProxy(\"getDefaultGuestRestrictions\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"setDefaultGuestRestrictions\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"removeRestrictions\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"getUsers\", Collections.EMPTY_LIST));\n        addMethodProxy(new ResultStaticMethodProxy(\"createUser\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"createProfileForUser\", null));\n        addMethodProxy(new ResultStaticMethodProxy(\"getProfiles\", Collections.EMPTY_LIST));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/vibrator/VibratorStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.vibrator;\n\nimport android.content.Context;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\n\nimport java.lang.reflect.Method;\n\nimport mirror.com.android.internal.os.IVibratorService;\n\n/**\n * @author Lody\n * @see android.os.Vibrator\n */\npublic class VibratorStub extends BinderInvocationProxy {\n\n    public VibratorStub() {\n        super(IVibratorService.Stub.asInterface, Context.VIBRATOR_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        //Samsung  {\n        addMethodProxy(new VibrateMethodProxy(\"vibrateMagnitude\"));\n        addMethodProxy(new VibrateMethodProxy(\"vibratePatternMagnitude\"));\n        // }\n        addMethodProxy(new VibrateMethodProxy(\"vibrate\"));\n        addMethodProxy(new VibrateMethodProxy(\"vibratePattern\"));\n    }\n\n    private final static class VibrateMethodProxy extends ReplaceCallingPkgMethodProxy {\n\n        private VibrateMethodProxy(String name) {\n            super(name);\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            if (args[0] instanceof Integer) {\n                args[0] = getRealUid();\n            }\n            return super.beforeCall(who, method, args);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/view/AutoFillManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.ComponentName;\nimport android.util.Log;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.ReplaceLastPkgMethodProxy;\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport mirror.android.view.IAutoFillManager;\n\n/**\n * @author 陈磊.\n */\n\npublic class AutoFillManagerStub extends BinderInvocationProxy {\n\n    private static final String TAG = \"AutoFillManagerStub\";\n\n    private static final String AUTO_FILL_NAME = \"autofill\";\n    public AutoFillManagerStub() {\n        super(IAutoFillManager.Stub.asInterface, AUTO_FILL_NAME);\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    @Override\n    public void inject() throws Throwable {\n        super.inject();\n        try {\n            Object AutoFillManagerInstance = getContext().getSystemService(AUTO_FILL_NAME);\n            if (AutoFillManagerInstance == null) {\n                throw new NullPointerException(\"AutoFillManagerInstance is null.\");\n            }\n            Object AutoFillManagerProxy = getInvocationStub().getProxyInterface();\n            if (AutoFillManagerProxy == null) {\n                throw new NullPointerException(\"AutoFillManagerProxy is null.\");\n            }\n            Field AutoFillManagerServiceField = AutoFillManagerInstance.getClass().getDeclaredField(\"mService\");\n            AutoFillManagerServiceField.setAccessible(true);\n            AutoFillManagerServiceField.set(AutoFillManagerInstance, AutoFillManagerProxy);\n        } catch (Throwable tr) {\n            Log.e(TAG, \"AutoFillManagerStub inject error.\", tr);\n            return;\n        }\n\n        addMethodProxy(new ReplacePkgAndComponentProxy(\"startSession\"));\n        addMethodProxy(new ReplacePkgAndComponentProxy(\"updateOrRestartSession\"));\n        addMethodProxy(new ReplaceLastPkgMethodProxy(\"isServiceEnabled\"));\n    }\n\n    static class ReplacePkgAndComponentProxy extends ReplaceLastPkgMethodProxy {\n\n        ReplacePkgAndComponentProxy(String name) {\n            super(name);\n        }\n\n        @Override\n        public boolean beforeCall(Object who, Method method, Object... args) {\n            replaceLastAppComponent(args, getHostPkg());\n            return super.beforeCall(who, method, args);\n        }\n\n        static ComponentName replaceLastAppComponent(Object[] args, String hostPkg) {\n            int index = ArrayUtils.indexOfLast(args, ComponentName.class);\n            if (index != -1) {\n                ComponentName orig = (ComponentName) args[index];\n                ComponentName newComponent = new ComponentName(hostPkg, orig.getClassName());\n                args[index] = newComponent;\n                return newComponent;\n            }\n            return null;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/wifi/WifiManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.wifi;\n\nimport android.content.Context;\nimport android.net.DhcpInfo;\nimport android.net.wifi.ScanResult;\nimport android.net.wifi.SupplicantState;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.WorkSource;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.base.ReplaceCallingPkgMethodProxy;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.client.ipc.VirtualLocationManager;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.marks.FakeDeviceMark;\nimport com.lody.virtual.helper.utils.marks.FakeLocMark;\nimport com.lody.virtual.remote.vloc.VWifi;\n\nimport java.lang.reflect.Method;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport mirror.android.net.wifi.IWifiManager;\nimport mirror.android.net.wifi.WifiSsid;\n\n/**\n * @author Lody\n * @see android.net.wifi.WifiManager\n */\npublic class WifiManagerStub extends BinderInvocationProxy {\n\n    private class RemoveWorkSourceMethodProxy extends StaticMethodProxy {\n\n        RemoveWorkSourceMethodProxy(String name) {\n            super(name);\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            int index = ArrayUtils.indexOfFirst(args, WorkSource.class);\n            if (index >= 0) {\n                args[index] = null;\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n\n    public WifiManagerStub() {\n        super(IWifiManager.Stub.asInterface, Context.WIFI_SERVICE);\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new MethodProxy() {\n            @Override\n            public String getMethodName() {\n                return \"isWifiEnabled\";\n            }\n\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                if (VASettings.Wifi.FAKE_WIFI_STATE) {\n                    return true;\n                }\n                return super.call(who, method, args);\n            }\n        });\n        addMethodProxy(new MethodProxy() {\n            @Override\n            public String getMethodName() {\n                return \"getWifiEnabledState\";\n            }\n\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                if (VASettings.Wifi.FAKE_WIFI_STATE) {\n                    return WifiManager.WIFI_STATE_ENABLED;\n                }\n                return super.call(who, method, args);\n            }\n        });\n        addMethodProxy(new MethodProxy() {\n            @Override\n            public String getMethodName() {\n                return \"createDhcpInfo\";\n            }\n\n            @Override\n            public Object call(Object who, Method method, Object... args) throws Throwable {\n                if (VASettings.Wifi.FAKE_WIFI_STATE) {\n                    IPInfo ipInfo = getIPInfo();\n                    if (ipInfo != null) {\n                        return createDhcpInfo(ipInfo);\n                    }\n                }\n                return super.call(who, method, args);\n            }\n        });\n        addMethodProxy(new GetConnectionInfo());\n        addMethodProxy(new GetScanResults());\n        addMethodProxy(new ReplaceCallingPkgMethodProxy(\"getBatchedScanResults\"));\n        addMethodProxy(new RemoveWorkSourceMethodProxy(\"acquireWifiLock\"));\n        addMethodProxy(new RemoveWorkSourceMethodProxy(\"updateWifiLockWorkSource\"));\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {\n            addMethodProxy(new RemoveWorkSourceMethodProxy(\"startLocationRestrictedScan\"));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            addMethodProxy(new RemoveWorkSourceMethodProxy(\"startScan\"));\n            addMethodProxy(new RemoveWorkSourceMethodProxy(\"requestBatchedScan\"));\n        }\n    }\n\n    @FakeLocMark(\"Fake wifi bssid\")\n    @FakeDeviceMark(\"fake wifi MAC\")\n    private final class GetConnectionInfo extends MethodProxy {\n        @Override\n        public String getMethodName() {\n            return \"getConnectionInfo\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            WifiInfo wifiInfo = (WifiInfo) method.invoke(who, args);\n            if (isFakeLocationEnable()) {\n                mirror.android.net.wifi.WifiInfo.mBSSID.set(wifiInfo, \"00:00:00:00:00:00\");\n                mirror.android.net.wifi.WifiInfo.mMacAddress.set(wifiInfo, \"00:00:00:00:00:00\");\n            }\n            if (VASettings.Wifi.FAKE_WIFI_STATE) {\n                return createWifiInfo();\n            }\n            if (wifiInfo != null) {\n                mirror.android.net.wifi.WifiInfo.mMacAddress.set(wifiInfo, getDeviceInfo().wifiMac);\n            }\n            return wifiInfo;\n        }\n    }\n\n    @FakeLocMark(\"fake scan result\")\n    private final class GetScanResults extends ReplaceCallingPkgMethodProxy {\n\n        public GetScanResults() {\n            super(\"getScanResults\");\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n//            noinspection unchecked\n            if (isFakeLocationEnable()) {\n                new ArrayList<ScanResult>(0);\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n    private static ScanResult cloneScanResult(Parcelable scanResult) {\n        Parcel p = Parcel.obtain();\n        scanResult.writeToParcel(p, 0);\n        p.setDataPosition(0);\n        ScanResult newScanResult = Reflect.on(scanResult).field(\"CREATOR\").call(\"createFromParcel\", p).get();\n        p.recycle();\n        return newScanResult;\n    }\n\n    public static class IPInfo {\n        NetworkInterface intf;\n        InetAddress addr;\n        String ip;\n        int ip_hex;\n        int netmask_hex;\n    }\n\n\n    private static IPInfo getIPInfo() {\n        try {\n            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());\n            for (NetworkInterface intf : interfaces) {\n                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());\n                for (InetAddress addr : addrs) {\n                    if (!addr.isLoopbackAddress()) {\n                        String sAddr = addr.getHostAddress().toUpperCase();\n                        boolean isIPv4 = isIPv4Address(sAddr);\n                        if (isIPv4) {\n                            IPInfo info = new IPInfo();\n                            info.addr = addr;\n                            info.intf = intf;\n                            info.ip = sAddr;\n                            info.ip_hex = InetAddress_to_hex(addr);\n                            info.netmask_hex = netmask_to_hex(intf.getInterfaceAddresses().get(0).getNetworkPrefixLength());\n                            return info;\n                        }\n                    }\n                }\n            }\n        } catch (SocketException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    private static boolean isIPv4Address(String input) {\n        Pattern IPV4_PATTERN = Pattern.compile(\"^(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)(\\\\.(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)){3}$\");\n        return IPV4_PATTERN.matcher(input).matches();\n    }\n\n    private static int netmask_to_hex(int netmask_slash) {\n        int r = 0;\n        int b = 1;\n        for (int i = 0; i < netmask_slash; i++, b = b << 1)\n            r |= b;\n        return r;\n    }\n\n    private static int InetAddress_to_hex(InetAddress a) {\n        int result = 0;\n        byte b[] = a.getAddress();\n        for (int i = 0; i < 4; i++)\n            result |= (b[i] & 0xff) << (8 * i);\n        return result;\n    }\n\n    private DhcpInfo createDhcpInfo(IPInfo ip) {\n        DhcpInfo i = new DhcpInfo();\n        i.ipAddress = ip.ip_hex;\n        i.netmask = ip.netmask_hex;\n        i.dns1 = 0x04040404;\n        i.dns2 = 0x08080808;\n        return i;\n    }\n\n    private static WifiInfo createWifiInfo() throws Exception {\n        WifiInfo info = mirror.android.net.wifi.WifiInfo.ctor.newInstance();\n        IPInfo ip = getIPInfo();\n        InetAddress address = (ip != null ? ip.addr : null);\n        mirror.android.net.wifi.WifiInfo.mNetworkId.set(info, 1);\n        mirror.android.net.wifi.WifiInfo.mSupplicantState.set(info, SupplicantState.COMPLETED);\n        mirror.android.net.wifi.WifiInfo.mBSSID.set(info, VASettings.Wifi.BSSID);\n        mirror.android.net.wifi.WifiInfo.mMacAddress.set(info, VASettings.Wifi.MAC);\n        mirror.android.net.wifi.WifiInfo.mIpAddress.set(info, address);\n        mirror.android.net.wifi.WifiInfo.mLinkSpeed.set(info, 65);\n        if (Build.VERSION.SDK_INT >= 21) {\n            mirror.android.net.wifi.WifiInfo.mFrequency.set(info, 5000); // MHz\n        }\n        mirror.android.net.wifi.WifiInfo.mRssi.set(info, 200); // MAX_RSSI\n        if (mirror.android.net.wifi.WifiInfo.mWifiSsid != null) {\n            mirror.android.net.wifi.WifiInfo.mWifiSsid.set(info, WifiSsid.createFromAsciiEncoded.call(VASettings.Wifi.SSID));\n        } else {\n            mirror.android.net.wifi.WifiInfo.mSSID.set(info, VASettings.Wifi.SSID);\n        }\n        return info;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/wifi_scanner/GhostWifiScannerImpl.java",
    "content": "package com.lody.virtual.client.hook.proxies.wifi_scanner;\n\nimport android.net.wifi.IWifiScanner;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Messenger;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\n\nimport mirror.android.net.wifi.WifiScanner;\n\n/**\n * @author Lody\n */\n\npublic class GhostWifiScannerImpl extends IWifiScanner.Stub {\n\n    private final Handler mHandler = new Handler(Looper.getMainLooper());\n\n    @Override\n    public Messenger getMessenger() throws RemoteException {\n        return new Messenger(mHandler);\n    }\n\n    @Override\n    public Bundle getAvailableChannels(int band) throws RemoteException {\n        Bundle bundle = new Bundle();\n        bundle.putIntegerArrayList(WifiScanner.GET_AVAILABLE_CHANNELS_EXTRA.get(), new ArrayList<Integer>(0));\n        return bundle;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/wifi_scanner/WifiScannerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.wifi_scanner;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\n\n/**\n * @author Lody\n */\n\npublic class WifiScannerStub extends BinderInvocationProxy {\n\n    public WifiScannerStub() {\n        super(new GhostWifiScannerImpl(), \"wifiscanner\");\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/window/MethodProxies.java",
    "content": "package com.lody.virtual.client.hook.proxies.window;\n\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.client.hook.proxies.window.session.WindowSessionPatch;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n\nclass MethodProxies {\n\n\n    static class OpenSession extends BasePatchSession {\n\n        @Override\n        public String getMethodName() {\n            return \"openSession\";\n        }\n    }\n\n\n    static class OverridePendingAppTransition extends BasePatchSession {\n\n        @Override\n        public String getMethodName() {\n            return \"overridePendingAppTransition\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (args[0] instanceof String) {\n                args[0] = getHostPkg();\n            }\n            return super.call(who, method, args);\n        }\n    }\n\n\n    static class OverridePendingAppTransitionInPlace extends MethodProxy {\n\n        @Override\n        public String getMethodName() {\n            return \"overridePendingAppTransitionInPlace\";\n        }\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            if (args[0] instanceof String) {\n                args[0] = getHostPkg();\n            }\n            return method.invoke(who, args);\n        }\n    }\n\n\n    static class SetAppStartingWindow extends BasePatchSession {\n\n        @Override\n        public String getMethodName() {\n            return \"setAppStartingWindow\";\n        }\n    }\n\n    abstract static class BasePatchSession extends MethodProxy {\n\n        @Override\n        public Object call(Object who, Method method, Object... args) throws Throwable {\n            Object session = method.invoke(who, args);\n            if (session instanceof IInterface) {\n                return proxySession((IInterface) session);\n            }\n            return session;\n        }\n\n        private Object proxySession(IInterface session) {\n            WindowSessionPatch windowSessionPatch = new WindowSessionPatch(session);\n            return windowSessionPatch.getInvocationStub().getProxyInterface();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/window/WindowManagerStub.java",
    "content": "package com.lody.virtual.client.hook.proxies.window;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.client.hook.base.BinderInvocationProxy;\nimport com.lody.virtual.client.hook.base.Inject;\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\n\nimport mirror.android.view.Display;\nimport mirror.android.view.IWindowManager;\nimport mirror.android.view.WindowManagerGlobal;\nimport mirror.com.android.internal.policy.PhoneWindow;\n\n/**\n * @author Lody\n */\n@Inject(MethodProxies.class)\npublic class WindowManagerStub extends BinderInvocationProxy {\n\n    public WindowManagerStub() {\n        super(IWindowManager.Stub.asInterface, Context.WINDOW_SERVICE);\n    }\n\n    @Override\n    public void inject() throws Throwable {\n        super.inject();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            if (WindowManagerGlobal.sWindowManagerService != null) {\n                WindowManagerGlobal.sWindowManagerService.set(getInvocationStub().getProxyInterface());\n            }\n        } else {\n            if (Display.sWindowManager != null) {\n                Display.sWindowManager.set(getInvocationStub().getProxyInterface());\n            }\n        }\n        if (PhoneWindow.TYPE != null) {\n            PhoneWindow.sWindowManager.set(getInvocationStub().getProxyInterface());\n        }\n    }\n\n    @Override\n    protected void onBindMethods() {\n        super.onBindMethods();\n        addMethodProxy(new StaticMethodProxy(\"addAppToken\"));\n        addMethodProxy(new StaticMethodProxy(\"setScreenCaptureDisabled\"));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/window/session/BaseMethodProxy.java",
    "content": "package com.lody.virtual.client.hook.proxies.window.session;\n\nimport android.view.WindowManager;\n\nimport com.lody.virtual.client.hook.base.StaticMethodProxy;\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author Lody\n */\n/*package*/ class BaseMethodProxy extends StaticMethodProxy {\n\n    public BaseMethodProxy(String name) {\n        super(name);\n    }\n\n    @Override\n    public Object call(Object who, Method method, Object... args) throws Throwable {\n        int index = ArrayUtils.indexOfFirst(args, WindowManager.LayoutParams.class);\n        if (index != -1) {\n            WindowManager.LayoutParams attrs = (WindowManager.LayoutParams) args[index];\n            if (attrs != null) {\n                attrs.packageName = getHostPkg();\n            }\n        }\n        return method.invoke(who, args);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/window/session/WindowSessionPatch.java",
    "content": "package com.lody.virtual.client.hook.proxies.window.session;\n\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.hook.base.MethodInvocationProxy;\nimport com.lody.virtual.client.hook.base.MethodInvocationStub;\n\n/**\n * @author Lody\n */\npublic class WindowSessionPatch extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {\n\n\tpublic WindowSessionPatch(IInterface session) {\n\t\tsuper(new MethodInvocationStub<>(session));\n\t}\n\n\t@Override\n\tpublic void onBindMethods() {\n\t\taddMethodProxy(new BaseMethodProxy(\"add\"));\n\t\taddMethodProxy(new BaseMethodProxy(\"addToDisplay\"));\n\t\taddMethodProxy(new BaseMethodProxy(\"addToDisplayWithoutInputChannel\"));\n\t\taddMethodProxy(new BaseMethodProxy(\"addWithoutInputChannel\"));\n\t\taddMethodProxy(new BaseMethodProxy(\"relayout\"));\n\n\t\t// http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/android/view/IWindowSession.aidl#51\n\t\tif (Build.VERSION.SDK_INT >= 30) {\n\t\t\taddMethodProxy(new BaseMethodProxy(\"addToDisplayAsUser\"));\n\t\t\taddMethodProxy(new BaseMethodProxy(\"grantInputChannel\"));\n\t\t}\n\t}\n\n\n\t@Override\n\tpublic void inject() throws Throwable {\n\t\t// <EMPTY>\n\t}\n\n\t@Override\n\tpublic boolean isEnvBad() {\n\t\treturn getInvocationStub().getProxyInterface() != null;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/secondary/HackAppUtils.java",
    "content": "package com.lody.virtual.client.hook.secondary;\n\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.ReflectException;\n\n/**\n * @author Lody\n */\n\npublic class HackAppUtils {\n\n    /**\n     * Enable the Log output of QQ.\n     *\n     * @param packageName package name\n     * @param classLoader class loader\n     */\n    public static void enableQQLogOutput(String packageName, ClassLoader classLoader) {\n        if (\"com.tencent.mobileqq\".equals(packageName)) {\n            try {\n                Reflect.on(\"com.tencent.qphone.base.util.QLog\", classLoader).set(\"UIN_REPORTLOG_LEVEL\", 100);\n            } catch (ReflectException e) {\n                // ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/secondary/ProxyServiceFactory.java",
    "content": "package com.lody.virtual.client.hook.secondary;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class ProxyServiceFactory {\n\n\tprivate static final String TAG = ProxyServiceFactory.class.getSimpleName();\n\n\tprivate static Map<String, ServiceFetcher> sHookSecondaryServiceMap = new HashMap<>();\n\n\tstatic {\n\t\tsHookSecondaryServiceMap.put(\"com.google.android.auth.IAuthManagerService\", new ServiceFetcher() {\n\t\t\t@Override\n\t\t\tpublic IBinder getService(final Context context, ClassLoader classLoader, IBinder binder) {\n\t\t\t\treturn new StubBinder(classLoader, binder) {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic InvocationHandler createHandler(Class<?> interfaceClass, final IInterface base) {\n\t\t\t\t\t\treturn new InvocationHandler() {\n\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\treturn method.invoke(base, args);\n\t\t\t\t\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\t\t\t\t\tif (e.getCause() != null) {\n\t\t\t\t\t\t\t\t\t\tthrow e.getCause();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\n\t\tsHookSecondaryServiceMap.put(\"com.android.vending.billing.IInAppBillingService\", new ServiceFetcher() {\n\t\t\t@Override\n\t\t\tpublic IBinder getService(final Context context, ClassLoader classLoader, IBinder binder) {\n\t\t\t\treturn new StubBinder(classLoader, binder) {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic InvocationHandler createHandler(Class<?> interfaceClass, final IInterface base) {\n\t\t\t\t\t\treturn new InvocationHandler() {\n\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\treturn method.invoke(base, args);\n\t\t\t\t\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\t\t\t\t\tif (e.getCause() != null) {\n\t\t\t\t\t\t\t\t\t\tthrow e.getCause();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\n\t\tsHookSecondaryServiceMap.put(\"com.google.android.gms.common.internal.IGmsServiceBroker\", new ServiceFetcher() {\n\t\t\t@Override\n\t\t\tpublic IBinder getService(final Context context, ClassLoader classLoader, IBinder binder) {\n\t\t\t\treturn new StubBinder(classLoader, binder) {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic InvocationHandler createHandler(Class<?> interfaceClass, final IInterface base) {\n\t\t\t\t\t\treturn new InvocationHandler() {\n\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\treturn method.invoke(base, args);\n\t\t\t\t\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\t\t\t\t\tif (e.getCause() != null) {\n\t\t\t\t\t\t\t\t\t\tthrow e.getCause();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthrow e;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\n\tpublic static IBinder getProxyService(Context context, ComponentName component, IBinder binder) {\n\t\tif (context == null || binder == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tString description = binder.getInterfaceDescriptor();\n\t\t\tServiceFetcher fetcher = sHookSecondaryServiceMap.get(description);\n\t\t\tif (fetcher != null) {\n\t\t\t\tIBinder res = fetcher.getService(context, context.getClassLoader(), binder);\n\t\t\t\tif (res != null) {\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Throwable e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\n\n\n\tprivate interface ServiceFetcher {\n\t\tIBinder getService(Context context, ClassLoader classLoader, IBinder binder);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/secondary/ServiceConnectionDelegate.java",
    "content": "package com.lody.virtual.client.hook.secondary;\n\nimport android.app.IServiceConnection;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.ServiceConnection;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.server.IBinderDelegateService;\n\nimport mirror.android.app.ActivityThread;\nimport mirror.android.app.ContextImpl;\nimport mirror.android.app.IServiceConnectionO;\nimport mirror.android.app.LoadedApk;\n\n/**\n * @author Lody\n */\n\npublic class ServiceConnectionDelegate extends IServiceConnection.Stub {\n    private final static ArrayMap<IBinder, ServiceConnectionDelegate> DELEGATE_MAP = new ArrayMap<>();\n    private IServiceConnection mConn;\n\n    private ServiceConnectionDelegate(IServiceConnection mConn) {\n        this.mConn = mConn;\n    }\n\n    public static IServiceConnection getDelegate(Context context, ServiceConnection connection,int flags) {\n        IServiceConnection sd = null;\n        if (connection == null) {\n            throw new IllegalArgumentException(\"connection is null\");\n        }\n        try {\n            Object activityThread = ActivityThread.currentActivityThread.call();\n            Object loadApk = ContextImpl.mPackageInfo.get(VirtualCore.get().getContext());\n            Handler handler = ActivityThread.getHandler.call(activityThread);\n            sd = LoadedApk.getServiceDispatcher.call(loadApk, connection, context, handler, flags);\n        } catch (Exception e) {\n            Log.e(\"ConnectionDelegate\", \"getServiceDispatcher\", e);\n        }\n        if (sd == null) {\n            throw new RuntimeException(\"Not supported in system context\");\n        }\n        return getDelegate(sd);\n    }\n\n    public static IServiceConnection removeDelegate(Context context, ServiceConnection conn) {\n        IServiceConnection connection = null;\n        try{\n            Object loadApk = ContextImpl.mPackageInfo.get(VirtualCore.get().getContext());\n            connection = LoadedApk.forgetServiceDispatcher.call(loadApk, context, conn);\n        }catch (Exception e){\n            Log.e(\"ConnectionDelegate\", \"forgetServiceDispatcher\", e);\n        }\n        if(connection == null){\n            return null;\n        }\n        return ServiceConnectionDelegate.removeDelegate(connection);\n    }\n\n    public static ServiceConnectionDelegate getDelegate(IServiceConnection conn) {\n        if(conn instanceof ServiceConnectionDelegate){\n            return (ServiceConnectionDelegate)conn;\n        }\n        IBinder binder = conn.asBinder();\n        ServiceConnectionDelegate delegate = DELEGATE_MAP.get(binder);\n        if (delegate == null) {\n            delegate = new ServiceConnectionDelegate(conn);\n            DELEGATE_MAP.put(binder, delegate);\n        }\n        return delegate;\n    }\n\n    public static ServiceConnectionDelegate removeDelegate(IServiceConnection conn) {\n        return DELEGATE_MAP.remove(conn.asBinder());\n    }\n\n    @Override\n    public void connected(ComponentName name, IBinder service) throws RemoteException {\n        connected(name, service, false);\n    }\n\n    public void connected(ComponentName name, IBinder service, boolean dead) throws RemoteException {\n        IBinderDelegateService delegateService = IBinderDelegateService.Stub.asInterface(service);\n        if (delegateService != null) {\n            name = delegateService.getComponent();\n            service = delegateService.getService();\n            IBinder proxy = ProxyServiceFactory.getProxyService(VClientImpl.get().getCurrentApplication(), name, service);\n            if (proxy != null) {\n                service = proxy;\n            }\n        }\n\n        if(Build.VERSION.SDK_INT>=26) {\n            IServiceConnectionO.connected.call(mConn, name, service, dead);\n        }else {\n            mConn.connected(name, service);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/secondary/StubBinder.java",
    "content": "package com.lody.virtual.client.hook.secondary;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.RemoteException;\n\nimport java.io.FileDescriptor;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.Proxy;\n\n/**\n * @author Lody\n */\n\nabstract class StubBinder implements IBinder {\n\tprivate ClassLoader mClassLoader;\n\tprivate IBinder mBase;\n\tprivate IInterface mInterface;\n\n\tStubBinder(ClassLoader classLoader, IBinder base) {\n\t\tthis.mClassLoader = classLoader;\n\t\tthis.mBase = base;\n\t}\n\n\t@Override\n\tpublic String getInterfaceDescriptor() throws RemoteException {\n\t\treturn mBase.getInterfaceDescriptor();\n\t}\n\n\t@Override\n\tpublic boolean pingBinder() {\n\t\treturn mBase.pingBinder();\n\t}\n\n\t@Override\n\tpublic boolean isBinderAlive() {\n\t\treturn mBase.isBinderAlive();\n\t}\n\n\n\t/**\n\t * Anti the Proguard.\n\t *\n\t * Search the AidlClass.Stub.asInterface(IBinder) method by the StackTrace.\n\t *\n\t */\n\t@Override\n\tpublic IInterface queryLocalInterface(String descriptor) {\n\t\tif (mInterface == null) {\n\t\t\tStackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();\n\t\t\tif (stackTrace == null || stackTrace.length <= 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tClass<?> aidlType = null;\n\t\t\tIInterface targetInterface = null;\n\n\t\t\tfor (StackTraceElement element : stackTrace) {\n\t\t\t\tif (element.isNativeMethod()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n                    Method method = mClassLoader.loadClass(element.getClassName())\n                            .getDeclaredMethod(element.getMethodName(), IBinder.class);\n                    if ((method.getModifiers() & Modifier.STATIC) != 0) {\n                        method.setAccessible(true);\n                        Class<?> returnType = method.getReturnType();\n                        if (returnType.isInterface() && IInterface.class.isAssignableFrom(returnType)) {\n                            aidlType = returnType;\n                            targetInterface = (IInterface) method.invoke(null, mBase);\n                        }\n                    }\n                } catch (Exception e) {\n                    // go to the next cycle\n                }\n\t\t\t}\n\t\t\tif (aidlType == null || targetInterface == null) {\n                return null;\n            }\n\t\t\tInvocationHandler handler = createHandler(aidlType, targetInterface);\n\t\t\tmInterface = (IInterface) Proxy.newProxyInstance(mClassLoader, new Class[]{aidlType}, handler);\n\t\t}\n\t\treturn mInterface;\n\n\t}\n\n\tpublic abstract InvocationHandler createHandler(Class<?> interfaceClass, IInterface iInterface);\n\n\n\t@Override\n\tpublic void dump(FileDescriptor fd, String[] args) throws RemoteException {\n\t\tmBase.dump(fd, args);\n\t}\n\n\t@Override\n\tpublic void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {\n\t\tmBase.dumpAsync(fd, args);\n\t}\n\n\t@Override\n\tpublic boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n\t\treturn mBase.transact(code, data, reply, flags);\n\t}\n\n\t@Override\n\tpublic void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {\n\t\tmBase.linkToDeath(recipient, flags);\n\t}\n\n\t@Override\n\tpublic boolean unlinkToDeath(DeathRecipient recipient, int flags) {\n\t\treturn mBase.unlinkToDeath(recipient, flags);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/utils/MethodParameterUtils.java",
    "content": "package com.lody.virtual.client.hook.utils;\n\nimport android.os.Process;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.ArrayUtils;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\n\n/**\n * @author Lody\n *\n */\npublic class MethodParameterUtils {\n\n\tpublic static <T> T getFirstParam(Object[] args, Class<T> tClass) {\n\t\tif (args == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint index = ArrayUtils.indexOfFirst(args, tClass);\n\t\tif (index != -1) {\n\t\t\treturn (T) args[index];\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static String replaceFirstAppPkg(Object[] args) {\n\t\tif (args == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint index = ArrayUtils.indexOfFirst(args, String.class);\n\t\tif (index != -1) {\n\t\t\tString pkg = (String) args[index];\n\t\t\targs[index] = VirtualCore.get().getHostPkg();\n\t\t\treturn pkg;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static String replaceLastAppPkg(Object[] args) {\n\t\tint index = ArrayUtils.indexOfLast(args, String.class);\n\t\tif (index != -1) {\n\t\t\tString pkg = (String) args[index];\n\t\t\targs[index] = VirtualCore.get().getHostPkg();\n\t\t\treturn pkg;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static void replaceLastUid(Object[] args) {\n\t\tint index = ArrayUtils.indexOfLast(args, Integer.class);\n\t\tif (index != -1) {\n\t\t\tint uid = (int) args[index];\n\t\t\tif (uid == Process.myUid()) {\n\t\t\t\targs[index] = VirtualCore.get().myUid();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static String replaceSequenceAppPkg(Object[] args, int sequence) {\n\t\tint index = ArrayUtils.indexOf(args, String.class, sequence);\n\t\tif (index != -1) {\n\t\t\tString pkg = (String) args[index];\n\t\t\targs[index] = VirtualCore.get().getHostPkg();\n\t\t\treturn pkg;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static Class<?>[] getAllInterface(Class clazz){\n\t\tHashSet<Class<?>> classes = new HashSet<>();\n\t\tgetAllInterfaces(clazz,classes);\n\t\tClass<?>[] result=new Class[classes.size()];\n\t\tclasses.toArray(result);\n\t\treturn result;\n\t}\n\n\n\tpublic static void getAllInterfaces(Class clazz, HashSet<Class<?>> interfaceCollection) {\n\t\tClass<?>[] classes = clazz.getInterfaces();\n\t\tif (classes.length != 0) {\n\t\t\tinterfaceCollection.addAll(Arrays.asList(classes));\n\t\t}\n\t\tif (clazz.getSuperclass() != Object.class) {\n\t\t\tgetAllInterfaces(clazz.getSuperclass(), interfaceCollection);\n\t\t}\n\t}\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/interfaces/IInjector.java",
    "content": "package com.lody.virtual.client.interfaces;\n\n/**\n * @author Lody\n *\n * The Objects who implemention this interface will be able to inject other object.\n *\n */\npublic interface IInjector {\n\n\t/**\n\t *\n     * Do injection.\n\t * \n\t * @throws Throwable if inject failed\n\t */\n\tvoid inject() throws Throwable;\n\n\t/**\n     * Check if the injection has bad.\n     *\n\t * @return If the injection has bad\n\t */\n\tboolean isEnvBad();\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/ActivityClientRecord.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.app.Activity;\nimport android.content.pm.ActivityInfo;\n\npublic class ActivityClientRecord {\n\tpublic Activity activity;\n\tpublic ActivityInfo info;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/LocalProxyUtils.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\n/**\n * @author Lody\n */\n\npublic class LocalProxyUtils {\n\n    /**\n     * Generates the Proxy instance for a base object, each IPC call will clean its calling identity.\n     * @param interfaceClass interface class\n     * @param base base object\n     * @return proxy object\n     */\n    public static <T> T genProxy(Class<T> interfaceClass, final Object base) {\n        //noinspection ConstantConditions\n        if (true) {\n            return (T) base;\n        }\n        //noinspection unchecked\n        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{ interfaceClass }, new InvocationHandler() {\n            @Override\n            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n                try {\n                    return method.invoke(base, args);\n                } catch (Throwable e) {\n                    throw e.getCause() == null ? e : e.getCause();\n                }\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/ProviderCall.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.compat.ContentProviderCompat;\n\nimport java.io.Serializable;\n\n/**\n * @author Lody\n *\n */\npublic class ProviderCall {\n\n\tpublic static Bundle call(String authority, String methodName, String arg, Bundle bundle) {\n\t\treturn call(authority, VirtualCore.get().getContext(), methodName, arg, bundle);\n\t}\n\n\tpublic static Bundle call(String authority, Context context, String method, String arg, Bundle bundle) {\n\t\tUri uri = Uri.parse(\"content://\" + authority);\n\t\treturn ContentProviderCompat.call(context, uri, method, arg, bundle);\n\t}\n\n\tpublic static final class Builder {\n\n\t\tprivate Context context;\n\n\t\tprivate Bundle bundle = new Bundle();\n\n\t\tprivate String method;\n\t\tprivate String auth;\n\t\tprivate String arg;\n\n\t\tpublic Builder(Context context, String auth) {\n\t\t\tthis.context = context;\n\t\t\tthis.auth = auth;\n\t\t}\n\n\t\tpublic Builder methodName(String name) {\n\t\t\tthis.method = name;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder arg(String arg) {\n\t\t\tthis.arg = arg;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder addArg(String key, Object value) {\n\t\t\tif (value != null) {\n\t\t\t\t if (value instanceof Boolean) {\n\t\t\t\t\tbundle.putBoolean(key, (Boolean) value);\n\t\t\t\t} else if (value instanceof Integer) {\n\t\t\t\t\tbundle.putInt(key, (Integer) value);\n\t\t\t\t} else if (value instanceof String) {\n\t\t\t\t\tbundle.putString(key, (String) value);\n\t\t\t\t} else if (value instanceof Serializable) {\n\t\t\t\t\tbundle.putSerializable(key, (Serializable) value);\n\t\t\t\t} else if (value instanceof Bundle) {\n\t\t\t\t\tbundle.putBundle(key, (Bundle) value);\n\t\t\t\t} else if (value instanceof Parcelable) {\n\t\t\t\t\tbundle.putParcelable(key, (Parcelable) value);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Unknown type \" + value.getClass() + \" in Bundle.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Bundle call() {\n\t\t\treturn ProviderCall.call(auth, context, method, arg, bundle);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/ServiceManagerNative.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.compat.BundleCompat;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.server.ServiceCache;\nimport com.lody.virtual.server.interfaces.IServiceFetcher;\n\n/**\n * @author Lody\n */\npublic class ServiceManagerNative {\n\n    public static final String PACKAGE = \"package\";\n    public static final String ACTIVITY = \"activity\";\n    public static final String USER = \"user\";\n    public static final String APP = \"app\";\n    public static final String ACCOUNT = \"account\";\n    public static final String JOB = \"job\";\n    public static final String NOTIFICATION = \"notification\";\n    public static final String VS = \"vs\";\n    public static final String DEVICE = \"device\";\n    public static final String VIRTUAL_LOC = \"virtual-loc\";\n\n    public static final String SERVICE_DEF_AUTH = \"virtual.service.BinderProvider\";\n    private static final String TAG = ServiceManagerNative.class.getSimpleName();\n    public static String SERVICE_CP_AUTH = \"virtual.service.BinderProvider\";\n\n    private static IServiceFetcher sFetcher;\n\n    private static IServiceFetcher getServiceFetcher() {\n        if (sFetcher == null || !sFetcher.asBinder().isBinderAlive()) {\n            synchronized (ServiceManagerNative.class) {\n                Context context = VirtualCore.get().getContext();\n                Bundle response = new ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName(\"@\").call();\n                if (response != null) {\n                    IBinder binder = BundleCompat.getBinder(response, \"_VA_|_binder_\");\n                    linkBinderDied(binder);\n                    sFetcher = IServiceFetcher.Stub.asInterface(binder);\n                }\n            }\n        }\n        return sFetcher;\n    }\n\n    public static void ensureServerStarted() {\n        new ProviderCall.Builder(VirtualCore.get().getContext(), SERVICE_CP_AUTH).methodName(\"ensure_created\").call();\n    }\n\n    public static void clearServerFetcher() {\n        sFetcher = null;\n    }\n\n    private static void linkBinderDied(final IBinder binder) {\n        IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {\n            @Override\n            public void binderDied() {\n                binder.unlinkToDeath(this, 0);\n            }\n        };\n        try {\n            binder.linkToDeath(deathRecipient, 0);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static IBinder getService(String name) {\n        if (VirtualCore.get().isServerProcess()) {\n            return ServiceCache.getService(name);\n        }\n        IServiceFetcher fetcher = getServiceFetcher();\n        if (fetcher != null) {\n            try {\n                return fetcher.getService(name);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        VLog.e(TAG, \"GetService(%s) return null.\", name);\n        return null;\n    }\n\n    public static void addService(String name, IBinder service) {\n        IServiceFetcher fetcher = getServiceFetcher();\n        if (fetcher != null) {\n            try {\n                fetcher.addService(name, service);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n\n    }\n\n    public static void removeService(String name) {\n        IServiceFetcher fetcher = getServiceFetcher();\n        if (fetcher != null) {\n            try {\n                fetcher.removeService(name);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VAccountManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManagerCallback;\nimport android.accounts.AccountManagerFuture;\nimport android.accounts.AuthenticatorDescription;\nimport android.accounts.IAccountManagerResponse;\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.stub.AmsTask;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.server.IAccountManager;\n\nimport static com.lody.virtual.helper.compat.AccountManagerCompat.KEY_ANDROID_PACKAGE_NAME;\n\n/**\n * @author Lody\n */\n\npublic class VAccountManager {\n\n    private static VAccountManager sMgr = new VAccountManager();\n\n    private IAccountManager mRemote;\n\n    public static VAccountManager get() {\n        return sMgr;\n    }\n\n    public IAccountManager getRemote() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (VAccountManager.class) {\n                Object remote = getStubInterface();\n                mRemote = LocalProxyUtils.genProxy(IAccountManager.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getStubInterface() {\n        return IAccountManager.Stub\n                .asInterface(ServiceManagerNative.getService(ServiceManagerNative.ACCOUNT));\n    }\n\n    public AuthenticatorDescription[] getAuthenticatorTypes() {\n        try {\n            return getRemote().getAuthenticatorTypes(VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void removeAccount(IAccountManagerResponse response, Account account, boolean expectActivityLaunch) {\n        try {\n            getRemote().removeAccount(VUserHandle.myUserId(), response, account, expectActivityLaunch);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void getAuthToken(IAccountManagerResponse response, Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, Bundle loginOptions) {\n        try {\n            getRemote().getAuthToken(VUserHandle.myUserId(), response, account, authTokenType, notifyOnAuthFailure, expectActivityLaunch, loginOptions);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean addAccountExplicitly(Account account, String password, Bundle extras) {\n        try {\n            return getRemote().addAccountExplicitly(VUserHandle.myUserId(), account, password, extras);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public Account[] getAccounts(int userId, String type) {\n        try {\n            return getRemote().getAccounts(userId, type);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public Account[] getAccounts(String type) {\n        try {\n            return getRemote().getAccounts(VUserHandle.myUserId(), type);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String peekAuthToken(Account account, String authTokenType) {\n        try {\n            return getRemote().peekAuthToken(VUserHandle.myUserId(), account, authTokenType);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getPreviousName(Account account) {\n        try {\n            return getRemote().getPreviousName(VUserHandle.myUserId(), account);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void hasFeatures(IAccountManagerResponse response, Account account, String[] features) {\n        try {\n            getRemote().hasFeatures(VUserHandle.myUserId(), response, account, features);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean accountAuthenticated(Account account) {\n        try {\n            return getRemote().accountAuthenticated(VUserHandle.myUserId(), account);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void clearPassword(Account account) {\n        try {\n            getRemote().clearPassword(VUserHandle.myUserId(), account);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void renameAccount(IAccountManagerResponse response, Account accountToRename, String newName) {\n        try {\n            getRemote().renameAccount(VUserHandle.myUserId(), response, accountToRename, newName);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void setPassword(Account account, String password) {\n        try {\n            getRemote().setPassword(VUserHandle.myUserId(), account, password);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void addAccount(int userId, IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn) {\n        try {\n            getRemote().addAccount(userId, response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void addAccount(IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn) {\n        try {\n            getRemote().addAccount(VUserHandle.myUserId(), response, accountType, authTokenType, requiredFeatures, expectActivityLaunch, optionsIn);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void updateCredentials(IAccountManagerResponse response, Account account, String authTokenType, boolean expectActivityLaunch, Bundle loginOptions) {\n        try {\n            getRemote().updateCredentials(VUserHandle.myUserId(), response, account, authTokenType, expectActivityLaunch, loginOptions);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean removeAccountExplicitly(Account account) {\n        try {\n            return getRemote().removeAccountExplicitly(VUserHandle.myUserId(), account);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setUserData(Account account, String key, String value) {\n        try {\n            getRemote().setUserData(VUserHandle.myUserId(), account, key, value);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void editProperties(IAccountManagerResponse response, String accountType, boolean expectActivityLaunch) {\n        try {\n            getRemote().editProperties(VUserHandle.myUserId(), response, accountType, expectActivityLaunch);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void getAuthTokenLabel(IAccountManagerResponse response, String accountType, String authTokenType) {\n        try {\n            getRemote().getAuthTokenLabel(VUserHandle.myUserId(), response, accountType, authTokenType);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void confirmCredentials(IAccountManagerResponse response, Account account, Bundle options, boolean expectActivityLaunch) {\n        try {\n            getRemote().confirmCredentials(VUserHandle.myUserId(), response, account, options, expectActivityLaunch);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void invalidateAuthToken(String accountType, String authToken) {\n        try {\n            getRemote().invalidateAuthToken(VUserHandle.myUserId(), accountType, authToken);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void getAccountsByFeatures(IAccountManagerResponse response, String type, String[] features) {\n        try {\n            getRemote().getAccountsByFeatures(VUserHandle.myUserId(), response, type, features);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void setAuthToken(Account account, String authTokenType, String authToken) {\n        try {\n            getRemote().setAuthToken(VUserHandle.myUserId(), account, authTokenType, authToken);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public Object getPassword(Account account) {\n        try {\n            return getRemote().getPassword(VUserHandle.myUserId(), account);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getUserData(Account account, String key) {\n        try {\n            return getRemote().getUserData(VUserHandle.myUserId(), account, key);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    /**\n     * Asks the user to add an account of a specified type.  The authenticator\n     * for this account type processes this request with the appropriate user\n     * interface.  If the user does elect to create a new account, the account\n     * name is returned.\n     * <p>\n     * <p>This method may be called from any thread, but the returned\n     * {@link AccountManagerFuture} must not be used on the main thread.\n     * <p>\n     *\n     */\n    public AccountManagerFuture<Bundle> addAccount(final int userId, final String accountType,\n                                                   final String authTokenType, final String[] requiredFeatures,\n                                                   final Bundle addAccountOptions,\n                                                   final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {\n        if (accountType == null) throw new IllegalArgumentException(\"accountType is null\");\n        final Bundle optionsIn = new Bundle();\n        if (addAccountOptions != null) {\n            optionsIn.putAll(addAccountOptions);\n        }\n        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, \"android\");\n\n        return new AmsTask(activity, handler, callback) {\n            @Override\n            public void doWork() throws RemoteException {\n                addAccount(userId, mResponse, accountType, authTokenType,\n                        requiredFeatures, activity != null, optionsIn);\n            }\n        }.start();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VActivityManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.app.Activity;\nimport android.app.IServiceConnection;\nimport android.app.Notification;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ProviderInfo;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.hook.secondary.ServiceConnectionDelegate;\nimport com.lody.virtual.helper.compat.ActivityManagerCompat;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.AppTaskInfo;\nimport com.lody.virtual.remote.BadgerInfo;\nimport com.lody.virtual.remote.PendingIntentData;\nimport com.lody.virtual.remote.PendingResultData;\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.server.IActivityManager;\nimport com.lody.virtual.server.interfaces.IProcessObserver;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.android.app.ActivityThread;\nimport mirror.android.content.ContentProviderNative;\n\n/**\n * @author Lody\n */\npublic class VActivityManager {\n\n    private static final VActivityManager sAM = new VActivityManager();\n    private final Map<IBinder, ActivityClientRecord> mActivities = new HashMap<IBinder, ActivityClientRecord>(6);\n    private IActivityManager mRemote;\n\n    public static VActivityManager get() {\n        return sAM;\n    }\n\n    public IActivityManager getService() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (VActivityManager.class) {\n                final Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IActivityManager.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n\n    private Object getRemoteInterface() {\n        return IActivityManager.Stub\n                .asInterface(ServiceManagerNative.getService(ServiceManagerNative.ACTIVITY));\n    }\n\n\n    public int startActivity(Intent intent, ActivityInfo info, IBinder resultTo, Bundle options, String resultWho, int requestCode, int userId) {\n        try {\n            return getService().startActivity(intent, info, resultTo, options, resultWho, requestCode, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int startActivities(Intent[] intents, String[] resolvedTypes, IBinder token, Bundle options, int userId) {\n        try {\n            return getService().startActivities(intents, resolvedTypes, token, options, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int startActivity(Intent intent, int userId) {\n        if (userId < 0) {\n            return ActivityManagerCompat.START_NOT_CURRENT_USER_ACTIVITY;\n        }\n        ActivityInfo info = VirtualCore.get().resolveActivityInfo(intent, userId);\n        if (info == null) {\n            return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;\n        }\n        return startActivity(intent, info, null, null, null, 0, userId);\n    }\n\n    public ActivityClientRecord onActivityCreate(ComponentName component, ComponentName caller, IBinder token, ActivityInfo info, Intent intent, String affinity, int taskId, int launchMode, int flags) {\n        ActivityClientRecord r = new ActivityClientRecord();\n        r.info = info;\n        mActivities.put(token, r);\n        try {\n            getService().onActivityCreated(component, caller, token, intent, affinity, taskId, launchMode, flags);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n        return r;\n    }\n\n    public ActivityClientRecord getActivityRecord(IBinder token) {\n        synchronized (mActivities) {\n            return token == null ? null : mActivities.get(token);\n        }\n    }\n\n    public void onActivityResumed(Activity activity) {\n        IBinder token = mirror.android.app.Activity.mToken.get(activity);\n        onActivityResumed(token);\n    }\n\n    public void onActivityResumed(IBinder token) {\n        try {\n            getService().onActivityResumed(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean onActivityDestroy(IBinder token) {\n        mActivities.remove(token);\n        try {\n            return getService().onActivityDestroyed(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public AppTaskInfo getTaskInfo(int taskId) {\n        try {\n            return getService().getTaskInfo(taskId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ComponentName getCallingActivity(IBinder token) {\n        try {\n            return getService().getCallingActivity(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getCallingPackage(IBinder token) {\n        try {\n            return getService().getCallingPackage(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getPackageForToken(IBinder token) {\n        try {\n            return getService().getPackageForToken(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ComponentName getActivityForToken(IBinder token) {\n        try {\n            return getService().getActivityClassForToken(VUserHandle.myUserId(), token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ComponentName startService(IInterface caller, Intent service, String resolvedType, int userId) {\n        try {\n            return getService().startService(caller != null ? caller.asBinder() : null, service, resolvedType, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int stopService(IInterface caller, Intent service, String resolvedType) {\n        try {\n            return getService().stopService(caller != null ? caller.asBinder() : null, service, resolvedType, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean stopServiceToken(ComponentName className, IBinder token, int startId) {\n        try {\n            return getService().stopServiceToken(className, token, startId, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification, boolean removeNotification) {\n        try {\n            getService().setServiceForeground(className, token, id, notification,removeNotification,  VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public int bindService(Context context, Intent service, ServiceConnection connection, int flags) {\n        try {\n            IServiceConnection conn = ServiceConnectionDelegate.getDelegate(context, connection, flags);\n            return getService().bindService(null, null, service, null, conn, flags, 0);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean unbindService(Context context, ServiceConnection connection) {\n        try {\n            IServiceConnection conn = ServiceConnectionDelegate.removeDelegate(context, connection);\n            return getService().unbindService(conn, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int bindService(IBinder caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) {\n        try {\n            return getService().bindService(caller, token, service, resolvedType, connection, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean unbindService(IServiceConnection connection) {\n        try {\n            return getService().unbindService(connection, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void unbindFinished(IBinder token, Intent service, boolean doRebind) {\n        try {\n            getService().unbindFinished(token, service, doRebind, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {\n        try {\n            getService().serviceDoneExecuting(token, type, startId, res, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public IBinder peekService(Intent service, String resolvedType) {\n        try {\n            return getService().peekService(service, resolvedType, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void publishService(IBinder token, Intent intent, IBinder service) {\n        try {\n            getService().publishService(token, intent, service, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public VParceledListSlice getServices(int maxNum, int flags) {\n        try {\n            return getService().getServices(maxNum, flags, VUserHandle.myUserId());\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void processRestarted(String packageName, String processName, int userId) {\n        try {\n            getService().processRestarted(packageName, processName, userId);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public String getAppProcessName(int pid) {\n        try {\n            return getService().getAppProcessName(pid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getInitialPackage(int pid) {\n        try {\n            return getService().getInitialPackage(pid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isAppProcess(String processName) {\n        try {\n            return getService().isAppProcess(processName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void handleApplicationCrash() {\n        try {\n            getService().handleApplicationCrash();\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void killAllApps() {\n        try {\n            getService().killAllApps();\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void killApplicationProcess(String procName, int uid) {\n        try {\n            getService().killApplicationProcess(procName, uid);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void registerProcessObserver(IProcessObserver observer) {\n        try {\n            getService().registerProcessObserver(observer);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void killAppByPkg(String pkg, int userId) {\n        try {\n            getService().killAppByPkg(pkg, userId);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void unregisterProcessObserver(IProcessObserver observer) {\n        try {\n            getService().unregisterProcessObserver(observer);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void appDoneExecuting() {\n        try {\n            getService().appDoneExecuting();\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public List<String> getProcessPkgList(int pid) {\n        try {\n            return getService().getProcessPkgList(pid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isAppPid(int pid) {\n        try {\n            return getService().isAppPid(pid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int getUidByPid(int pid) {\n        try {\n            return getService().getUidByPid(pid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int getSystemPid() {\n        try {\n            return getService().getSystemPid();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void sendActivityResult(IBinder resultTo, String resultWho, int requestCode) {\n        ActivityClientRecord r = mActivities.get(resultTo);\n        if (r != null && r.activity != null) {\n            Object mainThread = VirtualCore.mainThread();\n            ActivityThread.sendActivityResult.call(mainThread, resultTo, resultWho, requestCode, 0, null);\n        }\n    }\n\n    public IInterface acquireProviderClient(int userId, ProviderInfo info) throws RemoteException {\n        return ContentProviderNative.asInterface.call(getService().acquireProviderClient(userId, info));\n    }\n\n    public PendingIntentData getPendingIntent(IBinder binder) throws RemoteException {\n        return getService().getPendingIntent(binder);\n    }\n\n    public void addPendingIntent(IBinder binder, String creator) throws RemoteException {\n        getService().addPendingIntent(binder, creator);\n    }\n\n    public void removePendingIntent(IBinder binder) throws RemoteException {\n        getService().removePendingIntent(binder);\n    }\n\n    public void finishActivity(IBinder token) {\n        ActivityClientRecord r = getActivityRecord(token);\n        if (r != null) {\n            Activity activity = r.activity;\n            while (true) {\n                // We shouldn't use Activity.getParent(),\n                // because It may be overwritten.\n                Activity parent = mirror.android.app.Activity.mParent.get(activity);\n                if (parent == null) {\n                    break;\n                }\n                activity = parent;\n            }\n            // We shouldn't use Activity.isFinishing(),\n            // because It may be overwritten.\n            if (!mirror.android.app.Activity.mFinished.get(activity)) {\n                int resultCode = mirror.android.app.Activity.mResultCode.get(activity);\n                Intent resultData = mirror.android.app.Activity.mResultData.get(activity);\n                ActivityManagerCompat.finishActivity(token, resultCode, resultData);\n                mirror.android.app.Activity.mFinished.set(activity, true);\n            }\n        }\n    }\n\n    public boolean isAppRunning(String packageName, int userId) {\n        try {\n            return getService().isAppRunning(packageName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int initProcess(String packageName, String processName, int userId) {\n        try {\n            return getService().initProcess(packageName, processName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void sendBroadcast(Intent intent, int userId) {\n        Intent newIntent = ComponentUtils.redirectBroadcastIntent(intent, userId);\n        if (newIntent != null) {\n            VirtualCore.get().getContext().sendBroadcast(newIntent);\n        }\n    }\n\n    public boolean isVAServiceToken(IBinder token) {\n        try {\n            return getService().isVAServiceToken(token);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void broadcastFinish(PendingResultData res) {\n        try {\n            getService().broadcastFinish(res);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getPackageForIntentSender(IBinder binder) {\n        try {\n            return getService().getPackageForIntentSender(binder);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void notifyBadgerChange(BadgerInfo info) {\n        try {\n            getService().notifyBadgerChange(info);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VDeviceManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.remote.VDeviceInfo;\nimport com.lody.virtual.server.IDeviceInfoManager;\n\n/**\n * @author Lody\n */\n\npublic class VDeviceManager {\n\n    private static final VDeviceManager sInstance = new VDeviceManager();\n    private IDeviceInfoManager mRemote;\n\n\n    public static VDeviceManager get() {\n        return sInstance;\n    }\n\n\n    public IDeviceInfoManager getRemote() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (this) {\n                Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IDeviceInfoManager.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getRemoteInterface() {\n        final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.DEVICE);\n        return IDeviceInfoManager.Stub.asInterface(binder);\n    }\n\n    public VDeviceInfo getDeviceInfo(int userId) {\n        try {\n            return getRemote().getDeviceInfo(userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VJobScheduler.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.annotation.TargetApi;\nimport android.app.job.JobInfo;\nimport android.app.job.JobWorkItem;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.server.IJobScheduler;\n\nimport java.util.List;\n\n/**\n * @author Lody\n */\n\npublic class VJobScheduler {\n\n    private static final VJobScheduler sInstance = new VJobScheduler();\n\n    private IJobScheduler mRemote;\n\n    public static VJobScheduler get() {\n        return sInstance;\n    }\n\n    public IJobScheduler getRemote() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (this) {\n                Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IJobScheduler.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getRemoteInterface() {\n        final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.JOB);\n        return IJobScheduler.Stub.asInterface(binder);\n    }\n\n    public int schedule(JobInfo job) {\n        try {\n            return getRemote().schedule(job);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<JobInfo> getAllPendingJobs() {\n        try {\n            return getRemote().getAllPendingJobs();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void cancelAll() {\n        try {\n            getRemote().cancelAll();\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void cancel(int jobId) {\n        try {\n            getRemote().cancel(jobId);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n    public JobInfo getPendingJob(int jobId) {\n        try {\n            return getRemote().getPendingJob(jobId);\n        } catch (RemoteException e) {\n            return (JobInfo) VirtualRuntime.crash(e);\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.O)\n    public int enqueue(JobInfo job, Object workItem) {\n        if (workItem == null) {\n            return -1;\n        }\n        try {\n            return getRemote().enqueue(job, (JobWorkItem) workItem);\n        } catch (RemoteException e) {\n            return (Integer) VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VNotificationManager.java",
    "content": "package com.lody.virtual.client.ipc;\r\n\r\nimport android.app.Notification;\r\nimport android.os.IBinder;\r\nimport android.os.RemoteException;\r\n\r\nimport com.lody.virtual.client.core.VirtualCore;\r\nimport com.lody.virtual.server.INotificationManager;\r\nimport com.lody.virtual.server.notification.NotificationCompat;\r\n\r\n/**\r\n * Fake notification manager\r\n */\r\npublic class VNotificationManager {\r\n    private static final VNotificationManager sInstance = new VNotificationManager();\r\n    private final NotificationCompat mNotificationCompat;\r\n    private INotificationManager mRemote;\r\n\r\n    private VNotificationManager() {\r\n        mNotificationCompat = NotificationCompat.create();\r\n    }\r\n\r\n    public static VNotificationManager get() {\r\n        return sInstance;\r\n    }\r\n\r\n    public INotificationManager getService() {\r\n        if (mRemote == null ||\r\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\r\n            synchronized (VNotificationManager.class) {\r\n                final IBinder pmBinder = ServiceManagerNative.getService(ServiceManagerNative.NOTIFICATION);\r\n                mRemote = INotificationManager.Stub.asInterface(pmBinder);\r\n            }\r\n        }\r\n        return mRemote;\r\n    }\r\n\r\n    public boolean dealNotification(int id, Notification notification, String packageName) {\r\n        if(notification == null)return false;\r\n        return VirtualCore.get().getHostPkg().equals(packageName)\r\n                || mNotificationCompat.dealNotification(id, notification, packageName);\r\n    }\r\n\r\n    public int dealNotificationId(int id, String packageName, String tag, int userId) {\r\n        try {\r\n            return getService().dealNotificationId(id, packageName, tag, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n        }\r\n        return id;\r\n    }\r\n\r\n    public String dealNotificationTag(int id, String packageName, String tag, int userId) {\r\n        try {\r\n            return getService().dealNotificationTag(id, packageName, tag, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n        }\r\n        return tag;\r\n    }\r\n\r\n    public boolean areNotificationsEnabledForPackage(String packageName, int userId) {\r\n        try {\r\n            return getService().areNotificationsEnabledForPackage(packageName, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n            return true;\r\n        }\r\n    }\r\n\r\n    public void setNotificationsEnabledForPackage(String packageName, boolean enable, int userId) {\r\n        try {\r\n            getService().setNotificationsEnabledForPackage(packageName, enable, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n\r\n    public void addNotification(int id, String tag, String packageName, int userId) {\r\n        try {\r\n            getService().addNotification(id, tag, packageName, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n\r\n    public void cancelAllNotification(String packageName, int userId) {\r\n        try {\r\n            getService().cancelAllNotification(packageName, userId);\r\n        } catch (RemoteException e) {\r\n            e.printStackTrace();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VPackageManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.server.IPackageInstaller;\nimport com.lody.virtual.server.IPackageManager;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * @author Lody\n */\npublic class VPackageManager {\n\n    private static final VPackageManager sMgr = new VPackageManager();\n    private IPackageManager mRemote;\n\n    public static VPackageManager get() {\n        return sMgr;\n    }\n\n    public IPackageManager getInterface() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (VPackageManager.class) {\n                Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IPackageManager.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getRemoteInterface() {\n        final IBinder pmBinder = ServiceManagerNative.getService(ServiceManagerNative.PACKAGE);\n        return IPackageManager.Stub.asInterface(pmBinder);\n    }\n\n    public int checkPermission(String permName, String pkgName, int userId) {\n        try {\n            return getInterface().checkPermission(permName, pkgName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().resolveService(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {\n        try {\n            return getInterface().getPermissionGroupInfo(name, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ApplicationInfo> getInstalledApplications(int flags, int userId) {\n        try {\n            // noinspection unchecked\n            return getInterface().getInstalledApplications(flags, userId).getList();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {\n        try {\n            return getInterface().getPackageInfo(packageName, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().resolveIntent(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().queryIntentContentProviders(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ActivityInfo getReceiverInfo(ComponentName componentName, int flags, int userId) {\n        try {\n            return getInterface().getReceiverInfo(componentName, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<PackageInfo> getInstalledPackages(int flags, int userId) {\n        try {\n            return getInterface().getInstalledPackages(flags, userId).getList();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {\n        try {\n            return getInterface().queryPermissionsByGroup(group, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public PermissionInfo getPermissionInfo(String name, int flags) {\n        try {\n            return getInterface().getPermissionInfo(name, flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ActivityInfo getActivityInfo(ComponentName componentName, int flags, int userId) {\n        try {\n            return getInterface().getActivityInfo(componentName, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().queryIntentReceivers(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {\n        try {\n            return getInterface().getAllPermissionGroups(flags);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().queryIntentActivities(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId) {\n        try {\n            return getInterface().queryIntentServices(intent, resolvedType, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {\n        try {\n            ApplicationInfo info = getInterface().getApplicationInfo(packageName, flags, userId);\n            if (info == null) {\n                return null;\n            }\n            final int P = 28;\n            String APACHE_LEGACY = \"/system/framework/org.apache.http.legacy.boot.jar\";\n            if (!new File(APACHE_LEGACY).exists()) {\n                APACHE_LEGACY = \"/system/framework/org.apache.http.legacy.jar\";\n            }\n            List<String> sharedLibraries = getInterface().getSharedLibraries(packageName);\n            boolean forceAdd = sharedLibraries.contains(\"org.apache.http.legacy\");\n\n            // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java;l=36?q=OrgApacheHttpLegacyUpdater&ss=android%2Fplatform%2Fsuperproject:frameworks%2Fbase%2Fservices%2Fcore%2Fjava%2Fcom%2Fandroid%2Fserver%2Fpm%2Fparsing%2Flibrary%2F\n            if (android.os.Build.VERSION.SDK_INT >= P && info.targetSdkVersion < P || forceAdd) {\n                String[] newSharedLibraryFiles;\n                if (info.sharedLibraryFiles == null) {\n                    newSharedLibraryFiles = new String[]{APACHE_LEGACY};\n                } else {\n                    int newLength = info.sharedLibraryFiles.length + 1;\n                    newSharedLibraryFiles = new String[newLength];\n                    System.arraycopy(info.sharedLibraryFiles, 0, newSharedLibraryFiles, 0, newLength - 1);\n                    newSharedLibraryFiles[newLength - 1] = APACHE_LEGACY;\n                }\n                info.sharedLibraryFiles = newSharedLibraryFiles;\n            }\n\n            String TEST_BASE = \"/system/framework/android.test.base.jar\";\n            if (BuildCompat.isR() && new File(TEST_BASE).exists()) {\n                String[] newSharedLibraryFiles;\n                if (info.sharedLibraryFiles == null) {\n                    newSharedLibraryFiles = new String[]{TEST_BASE};\n                } else {\n                    int newLength = info.sharedLibraryFiles.length + 1;\n                    newSharedLibraryFiles = new String[newLength];\n                    System.arraycopy(info.sharedLibraryFiles, 0, newSharedLibraryFiles, 0, newLength - 1);\n                    newSharedLibraryFiles[newLength - 1] = TEST_BASE;\n                }\n                info.sharedLibraryFiles = newSharedLibraryFiles;\n            }\n            return info;\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ProviderInfo resolveContentProvider(String name, int flags, int userId) {\n        try {\n            return getInterface().resolveContentProvider(name, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ServiceInfo getServiceInfo(ComponentName componentName, int flags, int userId) {\n        try {\n            return getInterface().getServiceInfo(componentName, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public ProviderInfo getProviderInfo(ComponentName componentName, int flags, int userId) {\n        try {\n            return getInterface().getProviderInfo(componentName, flags, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) {\n        try {\n            return getInterface().activitySupportsIntent(component, intent, resolvedType);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) {\n        try {\n            // noinspection unchecked\n            return getInterface().queryContentProviders(processName, uid, flags).getList();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<String> querySharedPackages(String packageName) {\n        try {\n            return getInterface().querySharedPackages(packageName);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String[] getPackagesForUid(int uid) {\n        try {\n            return getInterface().getPackagesForUid(uid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int getPackageUid(String packageName, int userId) {\n        try {\n            return getInterface().getPackageUid(packageName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getNameForUid(int uid) {\n        try {\n            return getInterface().getNameForUid(uid);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n\n    public IPackageInstaller getPackageInstaller() {\n        try {\n            return getInterface().getPackageInstaller();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualLocationManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.hook.base.MethodProxy;\nimport com.lody.virtual.remote.vloc.VCell;\nimport com.lody.virtual.remote.vloc.VLocation;\nimport com.lody.virtual.server.IVirtualLocationManager;\n\nimport java.util.List;\n\n/**\n * @author Lody\n */\n\npublic class VirtualLocationManager {\n\n    private static final VirtualLocationManager sInstance = new VirtualLocationManager();\n    private IVirtualLocationManager mRemote;\n\n    public static final int MODE_CLOSE = 0;\n    public static final int MODE_USE_GLOBAL = 1;\n    public static final int MODE_USE_SELF = 2;\n\n\n    public static VirtualLocationManager get() {\n        return sInstance;\n    }\n\n\n    public IVirtualLocationManager getRemote() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (this) {\n                Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IVirtualLocationManager.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getRemoteInterface() {\n        final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.VIRTUAL_LOC);\n        return IVirtualLocationManager.Stub.asInterface(binder);\n    }\n\n    public int getMode(int userId, String pkg) {\n        try {\n            return getRemote().getMode(userId, pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public int getMode() {\n        return getMode(MethodProxy.getAppUserId(), MethodProxy.getAppPkg());\n    }\n\n    public void setMode(int userId, String pkg, int mode) {\n        try {\n            getRemote().setMode(userId, pkg, mode);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setCell(int userId, String pkg, VCell cell) {\n        try {\n            getRemote().setCell(userId, pkg, cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setAllCell(int userId, String pkg, List<VCell> cell) {\n        try {\n            getRemote().setAllCell(userId, pkg, cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setNeighboringCell(int userId, String pkg, List<VCell> cell) {\n        try {\n            getRemote().setNeighboringCell(userId, pkg, cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public VCell getCell(int userId, String pkg) {\n        try {\n            return getRemote().getCell(userId, pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<VCell> getAllCell(int userId, String pkg) {\n        try {\n            return getRemote().getAllCell(userId, pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public List<VCell> getNeighboringCell(int userId, String pkg) {\n        try {\n            return getRemote().getNeighboringCell(userId, pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n\n    public void setGlobalCell(VCell cell) {\n        try {\n            getRemote().setGlobalCell(cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setGlobalAllCell(List<VCell> cell) {\n        try {\n            getRemote().setGlobalAllCell(cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setGlobalNeighboringCell(List<VCell> cell) {\n        try {\n            getRemote().setGlobalNeighboringCell(cell);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setLocation(int userId, String pkg, VLocation loc) {\n        try {\n            getRemote().setLocation(userId, pkg, loc);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public VLocation getLocation(int userId, String pkg) {\n        try {\n            return getRemote().getLocation(userId, pkg);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public VLocation getLocation() {\n        return getLocation(MethodProxy.getAppUserId(), MethodProxy.getAppPkg());\n    }\n\n    public void setGlobalLocation(VLocation loc) {\n        try {\n            getRemote().setGlobalLocation(loc);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public VLocation getGlobalLocation() {\n        try {\n            return getRemote().getGlobalLocation();\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/ipc/VirtualStorageManager.java",
    "content": "package com.lody.virtual.client.ipc;\n\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.server.IVirtualStorageService;\n\n/**\n * @author Lody\n */\n\npublic class VirtualStorageManager {\n\n    private static final VirtualStorageManager sInstance = new VirtualStorageManager();\n    private IVirtualStorageService mRemote;\n\n\n    public static VirtualStorageManager get() {\n        return sInstance;\n    }\n\n\n    public IVirtualStorageService getRemote() {\n        if (mRemote == null ||\n                (!mRemote.asBinder().pingBinder() && !VirtualCore.get().isVAppProcess())) {\n            synchronized (this) {\n                Object remote = getRemoteInterface();\n                mRemote = LocalProxyUtils.genProxy(IVirtualStorageService.class, remote);\n            }\n        }\n        return mRemote;\n    }\n\n    private Object getRemoteInterface() {\n        final IBinder binder = ServiceManagerNative.getService(ServiceManagerNative.VS);\n        return IVirtualStorageService.Stub.asInterface(binder);\n    }\n\n    public void setVirtualStorage(String packageName, int userId, String vsPath) {\n        try {\n            getRemote().setVirtualStorage(packageName, userId, vsPath);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public String getVirtualStorage(String packageName, int userId) {\n        try {\n            return getRemote().getVirtualStorage(packageName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n\n    public void setVirtualStorageState(String packageName, int userId, boolean enable) {\n        try {\n            getRemote().setVirtualStorageState(packageName, userId, enable);\n        } catch (RemoteException e) {\n            VirtualRuntime.crash(e);\n        }\n    }\n\n    public boolean isVirtualStorageEnable(String packageName, int userId) {\n        try {\n            return getRemote().isVirtualStorageEnable(packageName, userId);\n        } catch (RemoteException e) {\n            return VirtualRuntime.crash(e);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/natives/NativeMethods.java",
    "content": "package com.lody.virtual.client.natives;\n\nimport android.hardware.Camera;\nimport android.media.AudioRecord;\nimport android.os.Build;\n\nimport com.lody.virtual.helper.utils.EncodeUtils;\n\nimport java.lang.reflect.Method;\n\nimport dalvik.system.DexFile;\n\n/**\n * @author Lody\n */\npublic class NativeMethods {\n\n    public static int gCameraMethodType;\n    public static Method gCameraNativeSetup;\n\n    public static Method gOpenDexFileNative;\n\n    public static Method gAudioRecordNativeCheckPermission;\n\n    public static void init() {\n        // anti-virus, fuck ESET-NOD32: a variant of Android/AdDisplay.AdLock.AL potentially unwanted\n        final String openDexFileNative = EncodeUtils.decode(\"b3BlbkRleEZpbGVOYXRpdmU=\");\n        final String openDexFile = EncodeUtils.decode(\"b3BlbkRleEZpbGU=\");\n\n        String methodName =\n                Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? openDexFileNative : openDexFile;\n        for (Method method : DexFile.class.getDeclaredMethods()) {\n            if (method.getName().equals(methodName)) {\n                gOpenDexFileNative = method;\n                break;\n            }\n        }\n        if (gOpenDexFileNative == null) {\n            throw new RuntimeException(\"Unable to find method : \" + methodName);\n        }\n        gOpenDexFileNative.setAccessible(true);\n\n        gCameraMethodType = -1;\n        try {\n            gCameraNativeSetup = Camera.class.getDeclaredMethod(\"native_setup\", Object.class, int.class, String.class);\n            gCameraMethodType = 1;\n        } catch (NoSuchMethodException e) {\n            // ignore\n        }\n        if (gCameraNativeSetup == null) {\n            try {\n                gCameraNativeSetup = Camera.class.getDeclaredMethod(\"native_setup\", Object.class, int.class, int.class, String.class);\n                gCameraMethodType = 2;\n            } catch (NoSuchMethodException e) {\n                // ignore\n            }\n        }\n        // HuaWei common\n        if (gCameraNativeSetup == null) {\n            try {\n                gCameraNativeSetup = Camera.class.getDeclaredMethod(\"native_setup\", Object.class, int.class, int.class, String.class, boolean.class);\n                gCameraMethodType = 3;\n            } catch (NoSuchMethodException e) {\n                // ignore\n            }\n        }\n        // HUAWEI MediaPad X1 7.0\n        if (gCameraNativeSetup == null) {\n            try {\n                gCameraNativeSetup = Camera.class.getDeclaredMethod(\"native_setup\", Object.class, int.class, String.class, boolean.class);\n                gCameraMethodType = 4;\n            } catch (NoSuchMethodException e) {\n                // ignore\n            }\n        }\n        if (gCameraNativeSetup != null) {\n            gCameraNativeSetup.setAccessible(true);\n        }\n\n        for (Method mth : AudioRecord.class.getDeclaredMethods()) {\n            if (mth.getName().equals(\"native_check_permission\")\n                    && mth.getParameterTypes().length == 1\n                    && mth.getParameterTypes()[0] == String.class) {\n                gAudioRecordNativeCheckPermission = mth;\n                mth.setAccessible(true);\n                break;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/AmsTask.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.accounts.AccountManagerCallback;\nimport android.accounts.AccountManagerFuture;\nimport android.accounts.AuthenticatorException;\nimport android.accounts.IAccountManagerResponse;\nimport android.accounts.OperationCanceledException;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.IOException;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport static android.accounts.AccountManager.ERROR_CODE_BAD_ARGUMENTS;\nimport static android.accounts.AccountManager.ERROR_CODE_CANCELED;\nimport static android.accounts.AccountManager.ERROR_CODE_INVALID_RESPONSE;\nimport static android.accounts.AccountManager.ERROR_CODE_NETWORK_ERROR;\nimport static android.accounts.AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION;\nimport static android.accounts.AccountManager.KEY_INTENT;\nimport static com.lody.virtual.helper.compat.AccountManagerCompat.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE;\nimport static com.lody.virtual.helper.compat.AccountManagerCompat.ERROR_CODE_USER_RESTRICTED;\n\npublic abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {\n    protected final IAccountManagerResponse mResponse;\n    final Handler mHandler;\n    final AccountManagerCallback<Bundle> mCallback;\n    final Activity mActivity;\n\n    public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {\n        super(new Callable<Bundle>() {\n            @Override\n            public Bundle call() throws Exception {\n                throw new IllegalStateException(\"this should never be called\");\n            }\n        });\n\n        mHandler = handler;\n        mCallback = callback;\n        mActivity = activity;\n        mResponse = new Response();\n    }\n\n    public final AccountManagerFuture<Bundle> start() {\n        try {\n            doWork();\n        } catch (RemoteException e) {\n            setException(e);\n        }\n        return this;\n    }\n\n    @Override\n    protected void set(Bundle bundle) {\n        // TODO: somehow a null is being set as the result of the Future. Log this\n        // case to help debug where this is occurring. When this bug is fixed this\n        // condition statement should be removed.\n        if (bundle == null) {\n            VLog.e(\"AccountManager\", \"the bundle must not be null\", new Exception());\n\n        }\n        super.set(bundle);\n    }\n\n    public abstract void doWork() throws RemoteException;\n\n    private Bundle internalGetResult(Long timeout, TimeUnit unit)\n            throws OperationCanceledException, IOException, AuthenticatorException {\n        try {\n            if (timeout == null) {\n                return get();\n            } else {\n                return get(timeout, unit);\n            }\n        } catch (CancellationException e) {\n            throw new OperationCanceledException();\n        } catch (TimeoutException e) {\n            // fall through and cancel\n        } catch (InterruptedException e) {\n            // fall through and cancel\n        } catch (ExecutionException e) {\n            final Throwable cause = e.getCause();\n            if (cause instanceof IOException) {\n                throw (IOException) cause;\n            } else if (cause instanceof UnsupportedOperationException) {\n                throw new AuthenticatorException(cause);\n            } else if (cause instanceof AuthenticatorException) {\n                throw (AuthenticatorException) cause;\n            } else if (cause instanceof RuntimeException) {\n                throw (RuntimeException) cause;\n            } else if (cause instanceof Error) {\n                throw (Error) cause;\n            } else {\n                throw new IllegalStateException(cause);\n            }\n        } finally {\n            cancel(true /* interrupt if running */);\n        }\n        throw new OperationCanceledException();\n    }\n\n    @Override\n    public Bundle getResult()\n            throws OperationCanceledException, IOException, AuthenticatorException {\n        return internalGetResult(null, null);\n    }\n\n    @Override\n    public Bundle getResult(long timeout, TimeUnit unit)\n            throws OperationCanceledException, IOException, AuthenticatorException {\n        return internalGetResult(timeout, unit);\n    }\n\n    @Override\n    protected void done() {\n        if (mCallback != null) {\n            postToHandler(mHandler, mCallback, this);\n        }\n    }\n\n    /**\n     * Handles the responses from the AccountManager\n     */\n    private class Response extends IAccountManagerResponse.Stub {\n        @Override\n        public void onResult(Bundle bundle) {\n            Intent intent = bundle.getParcelable(KEY_INTENT);\n            if (intent != null && mActivity != null) {\n                // since the user provided an Activity we will silently start intents\n                // that we see\n                mActivity.startActivity(intent);\n                // leave the Future running to wait for the real response to this request\n            } else if (bundle.getBoolean(\"retry\")) {\n                try {\n                    doWork();\n                } catch (RemoteException e) {\n                    throw new RuntimeException(e);\n                }\n            } else {\n                set(bundle);\n            }\n        }\n\n        @Override\n        public void onError(int code, String message) {\n            if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED\n                    || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {\n                // the authenticator indicated that this request was canceled or we were\n                // forbidden to fulfill; cancel now\n                cancel(true /* mayInterruptIfRunning */);\n                return;\n            }\n            setException(convertErrorToException(code, message));\n        }\n    }\n\n    private Exception convertErrorToException(int code, String message) {\n        if (code == ERROR_CODE_NETWORK_ERROR) {\n            return new IOException(message);\n        }\n\n        if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {\n            return new UnsupportedOperationException(message);\n        }\n\n        if (code == ERROR_CODE_INVALID_RESPONSE) {\n            return new AuthenticatorException(message);\n        }\n\n        if (code == ERROR_CODE_BAD_ARGUMENTS) {\n            return new IllegalArgumentException(message);\n        }\n\n        return new AuthenticatorException(message);\n    }\n\n    private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,\n                               final AccountManagerFuture<Bundle> future) {\n        handler = handler == null ? VirtualRuntime.getUIHandler() : handler;\n        handler.post(new Runnable() {\n            @Override\n            public void run() {\n                callback.run(future);\n            }\n        });\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/ChooseAccountTypeActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.accounts.AccountManager;\nimport android.accounts.AuthenticatorDescription;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.Resources;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VAccountManager;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * @hide\n */\npublic class ChooseAccountTypeActivity extends Activity {\n    private static final String TAG = \"AccountChooser\";\n\n    private HashMap<String, AuthInfo> mTypeToAuthenticatorInfo = new HashMap<String, AuthInfo>();\n    private ArrayList<AuthInfo> mAuthenticatorInfosToDisplay;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes\n        Set<String> setOfAllowableAccountTypes = null;\n        String[] validAccountTypes = getIntent().getStringArrayExtra(\n                ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);\n        if (validAccountTypes != null) {\n            setOfAllowableAccountTypes = new HashSet<>(validAccountTypes.length);\n            Collections.addAll(setOfAllowableAccountTypes, validAccountTypes);\n        }\n\n        // create a map of account authenticators\n        buildTypeToAuthDescriptionMap();\n\n        // Create a list of authenticators that are allowable. Filter out those that\n        // don't match the allowable account types, if provided.\n        mAuthenticatorInfosToDisplay = new ArrayList<>(mTypeToAuthenticatorInfo.size());\n        for (Map.Entry<String, AuthInfo> entry: mTypeToAuthenticatorInfo.entrySet()) {\n            final String type = entry.getKey();\n            final AuthInfo info = entry.getValue();\n            if (setOfAllowableAccountTypes != null\n                    && !setOfAllowableAccountTypes.contains(type)) {\n                continue;\n            }\n            mAuthenticatorInfosToDisplay.add(info);\n        }\n\n        if (mAuthenticatorInfosToDisplay.isEmpty()) {\n            Bundle bundle = new Bundle();\n            bundle.putString(AccountManager.KEY_ERROR_MESSAGE, \"no allowable account types\");\n            setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));\n            finish();\n            return;\n        }\n\n        if (mAuthenticatorInfosToDisplay.size() == 1) {\n            setResultAndFinish(mAuthenticatorInfosToDisplay.get(0).desc.type);\n            return;\n        }\n\n        setContentView(R.layout.choose_account_type);\n        // Setup the list\n        ListView list = (ListView) findViewById(android.R.id.list);\n        // Use an existing ListAdapter that will map an array of strings to TextViews\n        list.setAdapter(new AccountArrayAdapter(this,\n                android.R.layout.simple_list_item_1, mAuthenticatorInfosToDisplay));\n        list.setChoiceMode(ListView.CHOICE_MODE_NONE);\n        list.setTextFilterEnabled(false);\n        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {\n                setResultAndFinish(mAuthenticatorInfosToDisplay.get(position).desc.type);\n            }\n        });\n    }\n\n    private void setResultAndFinish(final String type) {\n        Bundle bundle = new Bundle();\n        bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, type);\n        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));\n        VLog.v(TAG, \"ChooseAccountTypeActivity.setResultAndFinish: \"\n                + \"selected account type \" + type);\n        finish();\n    }\n\n    private void buildTypeToAuthDescriptionMap() {\n        for(AuthenticatorDescription desc : VAccountManager.get().getAuthenticatorTypes()) {\n            String name = null;\n            Drawable icon = null;\n            try {\n                Resources res = VirtualCore.get().getResources(desc.packageName);\n                icon = res.getDrawable(desc.iconId);\n                final CharSequence sequence = res.getText(desc.labelId);\n                name = sequence.toString();\n                name = sequence.toString();\n            } catch (Resources.NotFoundException e) {\n                // Nothing we can do much here, just log\n                VLog.w(TAG, \"No icon resource for account type \" + desc.type);\n            }\n            AuthInfo authInfo = new AuthInfo(desc, name, icon);\n            mTypeToAuthenticatorInfo.put(desc.type, authInfo);\n        }\n    }\n\n    private static class AuthInfo {\n        final AuthenticatorDescription desc;\n        final String name;\n        final Drawable drawable;\n\n        AuthInfo(AuthenticatorDescription desc, String name, Drawable drawable) {\n            this.desc = desc;\n            this.name = name;\n            this.drawable = drawable;\n        }\n    }\n\n    private static class ViewHolder {\n        ImageView icon;\n        TextView text;\n    }\n\n    private static class AccountArrayAdapter extends ArrayAdapter<AuthInfo> {\n        private LayoutInflater mLayoutInflater;\n        private ArrayList<AuthInfo> mInfos;\n\n        AccountArrayAdapter(Context context, int textViewResourceId,\n                            ArrayList<AuthInfo> infos) {\n            super(context, textViewResourceId, infos);\n            mInfos = infos;\n            mLayoutInflater = (LayoutInflater) context.getSystemService(\n                    Context.LAYOUT_INFLATER_SERVICE);\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ViewHolder holder;\n\n            if (convertView == null) {\n                convertView = mLayoutInflater.inflate(R.layout.choose_account_row, null);\n                holder = new ViewHolder();\n                holder.text = (TextView) convertView.findViewById(R.id.account_row_text);\n                holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);\n                convertView.setTag(holder);\n            } else {\n                holder = (ViewHolder) convertView.getTag();\n            }\n\n            holder.text.setText(mInfos.get(position).name);\n            holder.icon.setImageDrawable(mInfos.get(position).drawable);\n\n            return convertView;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/ChooseTypeAndAccountActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.accounts.AccountManagerCallback;\nimport android.accounts.AccountManagerFuture;\nimport android.accounts.AuthenticatorDescription;\nimport android.accounts.AuthenticatorException;\nimport android.accounts.OperationCanceledException;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.ipc.VAccountManager;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class ChooseTypeAndAccountActivity extends Activity\n        implements AccountManagerCallback<Bundle> {\n    private static final String TAG = \"AccountChooser\";\n\n    /**\n     * A Parcelable ArrayList of Account objects that limits the choosable accounts to those\n     * in this list, if this parameter is supplied.\n     */\n    public static final String EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST = \"allowableAccounts\";\n\n    /**\n     * A Parcelable ArrayList of String objects that limits the accounts to choose to those\n     * that match the types in this list, if this parameter is supplied. This list is also\n     * used to filter the allowable account types if add account is selected.\n     */\n    public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY = \"allowableAccountTypes\";\n\n    /**\n     * This is passed as the addAccountOptions parameter in AccountManager.addAccount()\n     * if it is called.\n     */\n    public static final String EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE = \"addAccountOptions\";\n\n    /**\n     * This is passed as the requiredFeatures parameter in AccountManager.addAccount()\n     * if it is called.\n     */\n    public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY =\n            \"addAccountRequiredFeatures\";\n\n    /**\n     * This is passed as the authTokenType string in AccountManager.addAccount()\n     * if it is called.\n     */\n    public static final String EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING = \"authTokenType\";\n\n    /**\n     * If set then the specified account is already \"selected\".\n     */\n    public static final String EXTRA_SELECTED_ACCOUNT = \"selectedAccount\";\n\n    /**\n     * Deprecated. Providing this extra to {@link ChooseTypeAndAccountActivity}\n     * will have no effect.\n     */\n    @Deprecated\n    public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =\n            \"alwaysPromptForAccount\";\n\n    /**\n     * If set then this string willb e used as the description rather than\n     * the default.\n     */\n    public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =\n            \"descriptionTextOverride\";\n\n    public static final int REQUEST_NULL = 0;\n    public static final int REQUEST_CHOOSE_TYPE = 1;\n    public static final int REQUEST_ADD_ACCOUNT = 2;\n\n    private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = \"pendingRequest\";\n    private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = \"existingAccounts\";\n    private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = \"selectedAccountName\";\n    private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = \"selectedAddAccount\";\n    private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = \"accountList\";\n    public static final String KEY_USER_ID = \"userId\";\n\n    private static final int SELECTED_ITEM_NONE = -1;\n\n    private Set<Account> mSetOfAllowableAccounts;\n    private Set<String> mSetOfRelevantAccountTypes;\n    private String mSelectedAccountName = null;\n    private boolean mSelectedAddNewAccount = false;\n    private String mDescriptionOverride;\n\n    private ArrayList<Account> mAccounts;\n    private int mPendingRequest = REQUEST_NULL;\n    private Parcelable[] mExistingAccounts = null;\n    private int mSelectedItemIndex;\n    private Button mOkButton;\n    private int mCallingUserId;\n    private boolean mDontShowPicker;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        // save some items we use frequently\n        final Intent intent = getIntent();\n\n        if (savedInstanceState != null) {\n            mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);\n            mExistingAccounts =\n                    savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);\n\n            // Makes sure that any user selection is preserved across orientation changes.\n            mSelectedAccountName = savedInstanceState.getString(\n                    KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);\n\n            mSelectedAddNewAccount = savedInstanceState.getBoolean(\n                    KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);\n            mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);\n            mCallingUserId = savedInstanceState.getInt(KEY_USER_ID);\n        } else {\n            mPendingRequest = REQUEST_NULL;\n            mExistingAccounts = null;\n            mCallingUserId = intent.getIntExtra(KEY_USER_ID, -1);\n            // If the selected account as specified in the intent matches one in the list we will\n            // show is as pre-selected.\n            Account selectedAccount = intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);\n            if (selectedAccount != null) {\n                mSelectedAccountName = selectedAccount.name;\n            }\n        }\n        VLog.v(TAG, \"selected account name is \" + mSelectedAccountName);\n\n        mSetOfAllowableAccounts = getAllowableAccountSet(intent);\n        mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);\n        mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);\n\n        mAccounts = getAcceptableAccountChoices(VAccountManager.get());\n\n        if (mDontShowPicker) {\n            super.onCreate(savedInstanceState);\n            return;\n        }\n\n        // In cases where the activity does not need to show an account picker, cut the chase\n        // and return the result directly. Eg:\n        // Single account -> select it directly\n        // No account -> launch add account activity directly\n        if (mPendingRequest == REQUEST_NULL) {\n            // If there are no relevant accounts and only one relevant account type go directly to\n            // add account. Otherwise let the user choose.\n            if (mAccounts.isEmpty()) {\n                setNonLabelThemeAndCallSuperCreate(savedInstanceState);\n                if (mSetOfRelevantAccountTypes.size() == 1) {\n                    runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());\n                } else {\n                    startChooseAccountTypeActivity();\n                }\n            }\n        }\n\n        String[] listItems = getListOfDisplayableOptions(mAccounts);\n        mSelectedItemIndex = getItemIndexToSelect(\n                mAccounts, mSelectedAccountName, mSelectedAddNewAccount);\n\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.choose_type_and_account);\n        overrideDescriptionIfSupplied(mDescriptionOverride);\n        populateUIAccountList(listItems);\n\n        // Only enable \"OK\" button if something has been selected.\n        mOkButton = (Button) findViewById(android.R.id.button2);\n        mOkButton.setEnabled(mSelectedItemIndex != SELECTED_ITEM_NONE);\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            Log.v(TAG, \"ChooseTypeAndAccountActivity.onDestroy()\");\n        }\n        super.onDestroy();\n    }\n\n    @Override\n    protected void onSaveInstanceState(final Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);\n        if (mPendingRequest == REQUEST_ADD_ACCOUNT) {\n            outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);\n        }\n        if (mSelectedItemIndex != SELECTED_ITEM_NONE) {\n            if (mSelectedItemIndex == mAccounts.size()) {\n                outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);\n            } else {\n                outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);\n                outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,\n                        mAccounts.get(mSelectedItemIndex).name);\n            }\n        }\n        outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);\n    }\n\n    public void onCancelButtonClicked(View view) {\n        onBackPressed();\n    }\n\n    public void onOkButtonClicked(View view) {\n        if (mSelectedItemIndex == mAccounts.size()) {\n            // Selected \"Add New Account\" option\n            startChooseAccountTypeActivity();\n        } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {\n            onAccountSelected(mAccounts.get(mSelectedItemIndex));\n        }\n    }\n\n    // Called when the choose account type activity (for adding an account) returns.\n    // If it was a success read the account and set it in the result. In all cases\n    // return the result and finish this activity.\n    @Override\n    protected void onActivityResult(final int requestCode, final int resultCode,\n                                    final Intent data) {\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            if (data != null && data.getExtras() != null) data.getExtras().keySet();\n            Bundle extras = data != null ? data.getExtras() : null;\n            Log.v(TAG, \"ChooseTypeAndAccountActivity.onActivityResult(reqCode=\" + requestCode\n                    + \", resCode=\" + resultCode + \", extras=\" + extras + \")\");\n        }\n\n        // we got our result, so clear the fact that we had a pending request\n        mPendingRequest = REQUEST_NULL;\n\n        if (resultCode == RESULT_CANCELED) {\n            // if canceling out of addAccount and the original state caused us to skip this,\n            // finish this activity\n            if (mAccounts.isEmpty()) {\n                setResult(Activity.RESULT_CANCELED);\n                finish();\n            }\n            return;\n        }\n\n        if (resultCode == RESULT_OK) {\n            if (requestCode == REQUEST_CHOOSE_TYPE) {\n                if (data != null) {\n                    String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);\n                    if (accountType != null) {\n                        runAddAccountForAuthenticator(accountType);\n                        return;\n                    }\n                }\n                Log.d(TAG, \"ChooseTypeAndAccountActivity.onActivityResult: unable to find account \"\n                        + \"type, pretending the request was canceled\");\n            } else if (requestCode == REQUEST_ADD_ACCOUNT) {\n                String accountName = null;\n                String accountType = null;\n\n                if (data != null) {\n                    accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);\n                    accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);\n                }\n\n                if (accountName == null || accountType == null) {\n                    Account[] currentAccounts = VAccountManager.get().getAccounts(mCallingUserId, null);\n                    Set<Account> preExistingAccounts = new HashSet<>();\n                    for (Parcelable accountParcel : mExistingAccounts) {\n                        preExistingAccounts.add((Account) accountParcel);\n                    }\n                    for (Account account : currentAccounts) {\n                        if (!preExistingAccounts.contains(account)) {\n                            accountName = account.name;\n                            accountType = account.type;\n                            break;\n                        }\n                    }\n                }\n\n                if (accountName != null || accountType != null) {\n                    setResultAndFinish(accountName, accountType);\n                    return;\n                }\n            }\n            Log.d(TAG, \"ChooseTypeAndAccountActivity.onActivityResult: unable to find added \"\n                    + \"account, pretending the request was canceled\");\n        }\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            Log.v(TAG, \"ChooseTypeAndAccountActivity.onActivityResult: canceled\");\n        }\n        setResult(Activity.RESULT_CANCELED);\n        finish();\n    }\n\n    protected void runAddAccountForAuthenticator(String type) {\n        if (Log.isLoggable(TAG, Log.VERBOSE)) {\n            Log.v(TAG, \"runAddAccountForAuthenticator: \" + type);\n        }\n        final Bundle options = getIntent().getBundleExtra(\n                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);\n        final String[] requiredFeatures = getIntent().getStringArrayExtra(\n                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);\n        final String authTokenType = getIntent().getStringExtra(\n                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);\n        VAccountManager.get().addAccount(mCallingUserId, type, authTokenType, requiredFeatures,\n                options, null /* activity */, this /* callback */, null /* Handler */);\n    }\n\n    @Override\n    public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {\n        try {\n            final Bundle accountManagerResult = accountManagerFuture.getResult();\n            final Intent intent = accountManagerResult.getParcelable(\n                    AccountManager.KEY_INTENT);\n            if (intent != null) {\n                mPendingRequest = REQUEST_ADD_ACCOUNT;\n                mExistingAccounts = VAccountManager.get().getAccounts(mCallingUserId, null);\n                intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);\n                startActivityForResult(intent, REQUEST_ADD_ACCOUNT);\n                return;\n            }\n        } catch (OperationCanceledException e) {\n            setResult(Activity.RESULT_CANCELED);\n            finish();\n            return;\n        } catch (IOException e) {\n        } catch (AuthenticatorException e) {\n        }\n        Bundle bundle = new Bundle();\n        bundle.putString(AccountManager.KEY_ERROR_MESSAGE, \"error communicating with server\");\n        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));\n        finish();\n    }\n\n    /**\n     * The default activity theme shows label at the top. Set a theme which does\n     * not show label, which effectively makes the activity invisible. Note that\n     * no content is being set. If something gets set, using this theme may be\n     * useless.\n     */\n    private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            setTheme(android.R.style.Theme_Material_Light_Dialog_NoActionBar);\n        } else {\n            setTheme(android.R.style.Theme_Holo_Light_Dialog_NoActionBar);\n        }\n        super.onCreate(savedInstanceState);\n    }\n\n    private void onAccountSelected(Account account) {\n        Log.d(TAG, \"selected account \" + account);\n        setResultAndFinish(account.name, account.type);\n    }\n\n    private void setResultAndFinish(final String accountName, final String accountType) {\n        Bundle bundle = new Bundle();\n        bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);\n        bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);\n        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));\n        VLog.v(TAG, \"ChooseTypeAndAccountActivity.setResultAndFinish: \"\n                + \"selected account \" + accountName + \", \" + accountType);\n        finish();\n    }\n\n    private void startChooseAccountTypeActivity() {\n        VLog.v(TAG, \"ChooseAccountTypeActivity.startChooseAccountTypeActivity()\");\n        final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);\n        intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,\n                getIntent().getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));\n        intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,\n                getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));\n        intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,\n                getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));\n        intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,\n                getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));\n        startActivityForResult(intent, REQUEST_CHOOSE_TYPE);\n        mPendingRequest = REQUEST_CHOOSE_TYPE;\n    }\n\n    /**\n     * @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.\n     * An index value of accounts.size() indicates 'Add account' option.\n     */\n    private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,\n                                     boolean selectedAddNewAccount) {\n        // If \"Add account\" option was previously selected by user, preserve it across\n        // orientation changes.\n        if (selectedAddNewAccount) {\n            return accounts.size();\n        }\n        // search for the selected account name if present\n        for (int i = 0; i < accounts.size(); i++) {\n            if (accounts.get(i).name.equals(selectedAccountName)) {\n                return i;\n            }\n        }\n        // no account selected.\n        return SELECTED_ITEM_NONE;\n    }\n\n    private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {\n        // List of options includes all accounts found together with \"Add new account\" as the\n        // last item in the list.\n        String[] listItems = new String[accounts.size() + 1];\n        for (int i = 0; i < accounts.size(); i++) {\n            listItems[i] = accounts.get(i).name;\n        }\n        listItems[accounts.size()] = getResources().getString(\n                R.string.add_account_button_label);\n        return listItems;\n    }\n\n    /**\n     * Create a list of Account objects for each account that is acceptable. Filter out\n     * accounts that don't match the allowable types, if provided, or that don't match the\n     * allowable accounts, if provided.\n     */\n    private ArrayList<Account> getAcceptableAccountChoices(VAccountManager accountManager) {\n        final Account[] accounts = accountManager.getAccounts(mCallingUserId, null);\n        ArrayList<Account> accountsToPopulate = new ArrayList<>(accounts.length);\n        for (Account account : accounts) {\n            if (mSetOfAllowableAccounts != null && !mSetOfAllowableAccounts.contains(account)) {\n                continue;\n            }\n            if (mSetOfRelevantAccountTypes != null\n                    && !mSetOfRelevantAccountTypes.contains(account.type)) {\n                continue;\n            }\n            accountsToPopulate.add(account);\n        }\n        return accountsToPopulate;\n    }\n\n    /**\n     * Return a set of account types specified by the intent as well as supported by the\n     * AccountManager.\n     */\n    private Set<String> getReleventAccountTypes(final Intent intent) {\n        // An account type is relevant iff it is allowed by the caller and supported by the account\n        // manager.\n        Set<String> setOfRelevantAccountTypes;\n        final String[] allowedAccountTypes =\n                intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);\n        AuthenticatorDescription[] descs = VAccountManager.get().getAuthenticatorTypes();\n        Set<String> supportedAccountTypes = new HashSet<String>(descs.length);\n        for (AuthenticatorDescription desc : descs) {\n            supportedAccountTypes.add(desc.type);\n        }\n        if (allowedAccountTypes != null) {\n            setOfRelevantAccountTypes = new HashSet<>();\n            Collections.addAll(setOfRelevantAccountTypes, allowedAccountTypes);\n            setOfRelevantAccountTypes.retainAll(supportedAccountTypes);\n        } else {\n            setOfRelevantAccountTypes = supportedAccountTypes;\n        }\n        return setOfRelevantAccountTypes;\n    }\n\n    /**\n     * Returns a set of whitelisted accounts given by the intent or null if none specified by the\n     * intent.\n     */\n    private Set<Account> getAllowableAccountSet(final Intent intent) {\n        Set<Account> setOfAllowableAccounts = null;\n        final ArrayList<Parcelable> validAccounts =\n                intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);\n        if (validAccounts != null) {\n            setOfAllowableAccounts = new HashSet<>(validAccounts.size());\n            for (Parcelable parcelable : validAccounts) {\n                setOfAllowableAccounts.add((Account) parcelable);\n            }\n        }\n        return setOfAllowableAccounts;\n    }\n\n    /**\n     * Overrides the description text view for the picker activity if specified by the intent.\n     * If not specified then makes the description invisible.\n     */\n    private void overrideDescriptionIfSupplied(String descriptionOverride) {\n        TextView descriptionView = (TextView) findViewById(R.id.description);\n        if (!TextUtils.isEmpty(descriptionOverride)) {\n            descriptionView.setText(descriptionOverride);\n        } else {\n            descriptionView.setVisibility(View.GONE);\n        }\n    }\n\n    /**\n     * Populates the UI ListView with the given list of items and selects an item\n     * based on {@code mSelectedItemIndex} member variable.\n     */\n    private void populateUIAccountList(String[] listItems) {\n        ListView list = (ListView) findViewById(android.R.id.list);\n        list.setAdapter(new ArrayAdapter<>(this,\n                android.R.layout.simple_list_item_single_choice, listItems));\n        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);\n        list.setItemsCanFocus(false);\n        list.setOnItemClickListener(\n                new AdapterView.OnItemClickListener() {\n                    @Override\n                    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {\n                        mSelectedItemIndex = position;\n                        mOkButton.setEnabled(true);\n                    }\n                });\n        if (mSelectedItemIndex != SELECTED_ITEM_NONE) {\n            list.setItemChecked(mSelectedItemIndex, true);\n            VLog.v(TAG, \"List item \" + mSelectedItemIndex + \" should be selected\");\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/ChooserActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VUserHandle;\n\npublic class ChooserActivity extends ResolverActivity {\n    public static final String EXTRA_DATA = \"android.intent.extra.virtual.data\";\n    public static final String EXTRA_WHO = \"android.intent.extra.virtual.who\";\n    public static final String EXTRA_REQUEST_CODE = \"android.intent.extra.virtual.request_code\";\n    public static final String ACTION;\n\n    static {\n        Intent target = new Intent();\n        Intent intent = Intent.createChooser(target, \"\");\n        ACTION = intent.getAction();\n    }\n    public static boolean check(Intent intent) {\n        try {\n            return TextUtils.equals(ACTION, intent.getAction())\n                    ||TextUtils.equals(Intent.ACTION_CHOOSER, intent.getAction());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    @SuppressLint(\"MissingSuperCall\")\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        Intent intent = getIntent();\n        int userId = intent.getIntExtra(Constants.EXTRA_USER_HANDLE, VUserHandle.getCallingUserId());\n        mOptions = intent.getParcelableExtra(EXTRA_DATA);\n        mResultWho = intent.getStringExtra(EXTRA_WHO);\n        mRequestCode = intent.getIntExtra(EXTRA_REQUEST_CODE, 0);\n        Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);\n        if (!(targetParcelable instanceof Intent)) {\n            VLog.w(\"ChooseActivity\", \"Target is not an intent: \" + targetParcelable);\n            finish();\n            return;\n        }\n        Intent target = (Intent) targetParcelable;\n        CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);\n        if (title == null) {\n            title = getString(R.string.choose);\n        }\n        Parcelable[] pa = intent.getParcelableArrayExtra(Intent.EXTRA_INITIAL_INTENTS);\n        Intent[] initialIntents = null;\n        if (pa != null) {\n            initialIntents = new Intent[pa.length];\n            for (int i = 0; i < pa.length; i++) {\n                if (!(pa[i] instanceof Intent)) {\n                    VLog.w(\"ChooseActivity\", \"Initial intent #\" + i\n                            + \" not an Intent: \" + pa[i]);\n                    finish();\n                    return;\n                }\n                initialIntents[i] = (Intent) pa[i];\n            }\n        }\n        super.onCreate(savedInstanceState, target, title, initialIntents, null, false, userId);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/DaemonJobService.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.annotation.TargetApi;\nimport android.app.job.JobInfo;\nimport android.app.job.JobParameters;\nimport android.app.job.JobScheduler;\nimport android.app.job.JobService;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.lody.virtual.server.pm.PrivilegeAppOptimizer;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * author: weishu on 2018/4/10.\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class DaemonJobService extends JobService {\n\n    @Override\n    public boolean onStartJob(JobParameters params) {\n        PrivilegeAppOptimizer.notifyBootFinish();\n        return true;\n    }\n\n    @Override\n    public boolean onStopJob(JobParameters params) {\n        return false;\n    }\n\n    public static void scheduleJob(Context context) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {\n            return;\n        }\n\n        try {\n            JobScheduler jobScheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);\n\n            if (jobScheduler == null) {\n                return;\n            }\n\n            JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(context, DaemonJobService.class))\n                    .setRequiresCharging(false)\n                    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)\n                    .setPeriodic(TimeUnit.MINUTES.toMillis(15))\n                    .build();\n\n            jobScheduler.schedule(jobInfo);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/DaemonService.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.app.Notification;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.IBinder;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\n\nimport java.io.File;\n\n\n/**\n * @author Lody\n *\n */\npublic class DaemonService extends Service {\n\n    private static final int NOTIFY_ID = 1001;\n\n\tstatic boolean showNotification = true;\n\n\tpublic static void startup(Context context) {\n\t\tFile flagFile = context.getFileStreamPath(Constants.NO_NOTIFICATION_FLAG);\n\t\tif (Build.VERSION.SDK_INT >= 25 && flagFile.exists()) {\n\t\t\tshowNotification = false;\n\t\t}\n\n\t\tcontext.startService(new Intent(context, DaemonService.class));\n\t\tif (VirtualCore.get().isServerProcess()) {\n\t\t\t// PrivilegeAppOptimizer.notifyBootFinish();\n\t\t\tDaemonJobService.scheduleJob(context);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onDestroy() {\n\t\tsuper.onDestroy();\n\t\tstartup(this);\n\t}\n\n\t@Override\n\tpublic IBinder onBind(Intent intent) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void onCreate() {\n\t\tsuper.onCreate();\n\t\tif (!showNotification) {\n\t\t\treturn;\n\t\t}\n        startService(new Intent(this, InnerService.class));\n        startForeground(NOTIFY_ID, new Notification());\n\t}\n\n\t@Override\n\tpublic int onStartCommand(Intent intent, int flags, int startId) {\n\t\treturn START_STICKY;\n\t}\n\n\tpublic static final class InnerService extends Service {\n\n        @Override\n        public int onStartCommand(Intent intent, int flags, int startId) {\n            startForeground(NOTIFY_ID, new Notification());\n            stopForeground(true);\n            stopSelf();\n            return super.onStartCommand(intent, flags, startId);\n        }\n\n\t\t@Override\n\t\tpublic IBinder onBind(Intent intent) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/ResolverActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.app.ActivityManager;\nimport android.app.AlertDialog;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.LabeledIntent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.content.res.Resources;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.PatternMatcher;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.BaseAdapter;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VUserHandle;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\n\npublic class ResolverActivity extends Activity implements AdapterView.OnItemClickListener {\n    private static final String TAG = \"ResolverActivity\";\n    private static final boolean DEBUG = false;\n    protected Bundle mOptions;\n    protected String mResultWho;\n    protected int mRequestCode;\n    private int mLaunchedFromUid;\n    private ResolveListAdapter mAdapter;\n    private PackageManager mPm;\n    private boolean mAlwaysUseOption;\n    private boolean mShowExtended;\n    private ListView mListView;\n    private Button mAlwaysButton;\n    private Button mOnceButton;\n    private int mIconDpi;\n    private int mIconSize;\n    private int mMaxColumns;\n    private int mLastSelected = ListView.INVALID_POSITION;\n    private AlertDialog dialog;\n    private boolean mRegistered;\n\n    private Intent makeMyIntent() {\n        Intent intent = new Intent(getIntent());\n        intent.setComponent(null);\n        intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\n        return intent;\n    }\n\n    @SuppressLint(\"MissingSuperCall\")\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        final int titleResource;\n        final Intent intent = makeMyIntent();\n        final Set<String> categories = intent.getCategories();\n        if (Intent.ACTION_MAIN.equals(intent.getAction())\n                && categories != null\n                && categories.size() == 1\n                && categories.contains(Intent.CATEGORY_HOME)) {\n            titleResource = R.string.choose;\n        } else {\n            titleResource = R.string.choose;\n        }\n\n        onCreate(savedInstanceState, intent, getResources().getText(titleResource),\n                null, null, true, VUserHandle.getCallingUserId());\n    }\n\n    protected void onCreate(Bundle savedInstanceState, Intent intent,\n                            CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,\n                            boolean alwaysUseOption, int userid) {\n        super.onCreate(savedInstanceState);\n        mLaunchedFromUid = userid;\n        mPm = getPackageManager();\n        mAlwaysUseOption = alwaysUseOption;\n        mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);\n\n        mRegistered = true;\n\n        final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);\n        mIconDpi = am.getLauncherLargeIconDensity();\n        mIconSize = am.getLauncherLargeIconSize();\n\n        mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,\n                mLaunchedFromUid);\n        int count = mAdapter.getCount();\n        if (Build.VERSION.SDK_INT >= 17) {\n            if (mLaunchedFromUid < 0) {\n                // Gulp!\n                finish();\n                return;\n            }\n        }\n\n        if (count == 1) {\n            startSelected(0, false);\n            mRegistered = false;\n            finish();\n            return;\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(title);\n        if (count > 1) {\n            mListView = new ListView(this);\n            mListView.setAdapter(mAdapter);\n            mListView.setOnItemClickListener(this);\n            mListView.setOnItemLongClickListener(new ItemLongClickListener());\n            builder.setView(mListView);\n            if (alwaysUseOption) {\n                mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);\n            }\n        } else {\n            builder.setMessage(R.string.noApplications);\n        }\n        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {\n            @Override\n            public void onCancel(DialogInterface dialog) {\n                finish();\n            }\n        });\n        dialog = builder.show();\n//\n//        if (alwaysUseOption) {\n//            final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);\n//            if (buttonLayout != null) {\n//                buttonLayout.setVisibility(View.VISIBLE);\n//                mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);\n//                mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);\n//            } else {\n//                mAlwaysUseOption = false;\n//            }\n//            // Set the initial highlight if there was a preferred or last used choice\n//            final int initialHighlight = mAdapter.getInitialHighlight();\n//            if (initialHighlight >= 0) {\n//                mListView.setItemChecked(initialHighlight, true);\n//                onItemClick(null, null, initialHighlight, 0); // Other entries are not used\n//            }\n//        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (dialog != null && dialog.isShowing()) {\n            dialog.dismiss();\n        }\n        super.onDestroy();\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)\n    Drawable getIcon(Resources res, int resId) {\n        Drawable result;\n        try {\n            result = res.getDrawableForDensity(resId, mIconDpi);\n        } catch (Resources.NotFoundException e) {\n            result = null;\n        }\n\n        return result;\n    }\n\n    Drawable loadIconForResolveInfo(ResolveInfo ri) {\n        Drawable dr;\n        try {\n            if (ri.resolvePackageName != null && ri.icon != 0) {\n                dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);\n                if (dr != null) {\n                    return dr;\n                }\n            }\n            final int iconRes = ri.getIconResource();\n            if (iconRes != 0) {\n                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);\n                if (dr != null) {\n                    return dr;\n                }\n            }\n        } catch (PackageManager.NameNotFoundException e) {\n            VLog.e(TAG, \"Couldn't find resources for package\\n\" + VLog.getStackTraceString(e));\n        }\n        return ri.loadIcon(mPm);\n    }\n\n    @Override\n    protected void onRestart() {\n        super.onRestart();\n        if (!mRegistered) {\n            mRegistered = true;\n        }\n        mAdapter.handlePackagesChanged();\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        if (mRegistered) {\n            mRegistered = false;\n        }\n        if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {\n            // This resolver is in the unusual situation where it has been\n            // launched at the top of a new task.  We don't let it be added\n            // to the recent tasks shown to the user, and we need to make sure\n            // that each time we are launched we get the correct launching\n            // uid (not re-using the same resolver from an old launching uid),\n            // so we will now finish ourself since being no longer visible,\n            // the user probably can't get back to us.\n            if (!isChangingConfigurations()) {\n                finish();\n            }\n        }\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Bundle savedInstanceState) {\n        super.onRestoreInstanceState(savedInstanceState);\n        if (mAlwaysUseOption) {\n            final int checkedPos = mListView.getCheckedItemPosition();\n            final boolean enabled = checkedPos != ListView.INVALID_POSITION;\n            mLastSelected = checkedPos;\n            mAlwaysButton.setEnabled(enabled);\n            mOnceButton.setEnabled(enabled);\n            if (enabled) {\n                mListView.setSelection(checkedPos);\n            }\n        }\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        final int checkedPos = mListView.getCheckedItemPosition();\n        final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;\n        if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {\n            mAlwaysButton.setEnabled(hasValidSelection);\n            mOnceButton.setEnabled(hasValidSelection);\n            if (hasValidSelection) {\n                mListView.smoothScrollToPosition(checkedPos);\n            }\n            mLastSelected = checkedPos;\n        } else {\n            startSelected(position, false);\n        }\n    }\n\n    void startSelected(int which, boolean always) {\n        if (isFinishing()) {\n            return;\n        }\n        ResolveInfo ri = mAdapter.resolveInfoForPosition(which);\n        Intent intent = mAdapter.intentForPosition(which);\n        onIntentSelected(ri, intent, always);\n        finish();\n    }\n\n    protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {\n        if (mAlwaysUseOption && mAdapter.mOrigResolveList != null) {\n            // Build a reasonable intent filter, based on what matched.\n            IntentFilter filter = new IntentFilter();\n\n            if (intent.getAction() != null) {\n                filter.addAction(intent.getAction());\n            }\n            Set<String> categories = intent.getCategories();\n            if (categories != null) {\n                for (String cat : categories) {\n                    filter.addCategory(cat);\n                }\n            }\n            filter.addCategory(Intent.CATEGORY_DEFAULT);\n\n            int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;\n            Uri data = intent.getData();\n            if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {\n                String mimeType = intent.resolveType(this);\n                if (mimeType != null) {\n                    try {\n                        filter.addDataType(mimeType);\n                    } catch (IntentFilter.MalformedMimeTypeException e) {\n                        VLog.w(\"ResolverActivity\", \"mimeType\\n\" + VLog.getStackTraceString(e));\n                        filter = null;\n                    }\n                }\n            }\n            if (data != null && data.getScheme() != null) {\n                // We need the data specification if there was no type,\n                // OR if the scheme is not one of our magical \"file:\"\n                // or \"content:\" schemes (see IntentFilter for the reason).\n                if (cat != IntentFilter.MATCH_CATEGORY_TYPE\n                        || (!\"file\".equals(data.getScheme())\n                        && !\"content\".equals(data.getScheme()))) {\n                    filter.addDataScheme(data.getScheme());\n\n                    if (Build.VERSION.SDK_INT >= 19) {\n                        // Look through the resolved filter to determine which part\n                        // of it matched the original Intent.\n                        Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();\n                        if (pIt != null) {\n                            String ssp = data.getSchemeSpecificPart();\n                            while (ssp != null && pIt.hasNext()) {\n                                PatternMatcher p = pIt.next();\n                                if (p.match(ssp)) {\n                                    filter.addDataSchemeSpecificPart(p.getPath(), p.getType());\n                                    break;\n                                }\n                            }\n                        }\n                        Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();\n                        if (aIt != null) {\n                            while (aIt.hasNext()) {\n                                IntentFilter.AuthorityEntry a = aIt.next();\n                                if (a.match(data) >= 0) {\n                                    int port = a.getPort();\n                                    filter.addDataAuthority(a.getHost(),\n                                            port >= 0 ? Integer.toString(port) : null);\n                                    break;\n                                }\n                            }\n                        }\n                        pIt = ri.filter.pathsIterator();\n                        if (pIt != null) {\n                            String path = data.getPath();\n                            while (path != null && pIt.hasNext()) {\n                                PatternMatcher p = pIt.next();\n                                if (p.match(path)) {\n                                    filter.addDataPath(p.getPath(), p.getType());\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (filter != null) {\n                final int N = mAdapter.mOrigResolveList.size();\n                ComponentName[] set = new ComponentName[N];\n                int bestMatch = 0;\n                for (int i = 0; i < N; i++) {\n                    ResolveInfo r = mAdapter.mOrigResolveList.get(i);\n                    set[i] = new ComponentName(r.activityInfo.packageName,\n                            r.activityInfo.name);\n                    if (r.match > bestMatch) bestMatch = r.match;\n                }\n                if (alwaysCheck) {\n                    getPackageManager().addPreferredActivity(filter, bestMatch, set,\n                            intent.getComponent());\n                } else {\n                    try {\n                        Reflect.on(VClientImpl.get().getCurrentApplication().getPackageManager()).call(\"setLastChosenActivity\",\n                                intent,\n                                intent.resolveTypeIfNeeded(getContentResolver()),\n                                PackageManager.MATCH_DEFAULT_ONLY,\n                                filter, bestMatch, intent.getComponent());\n                    } catch (Exception re) {\n                        VLog.d(TAG, \"Error calling setLastChosenActivity\\n\" + VLog.getStackTraceString(re));\n                    }\n                }\n            }\n        }\n\n        if (intent != null) {\n            ActivityInfo info = VirtualCore.get().resolveActivityInfo(intent, mLaunchedFromUid);\n            if (info == null) {\n                //外面的\n                startActivity(intent);\n//                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n//                    startActivity(intent);//, mRequestCode, mOptions);\n//                }else{\n//                    startActivity(intent);//, mRequestCode);\n//                }\n            } else {\n                VActivityManager.get().startActivity(intent, info, null, mOptions, mResultWho, mRequestCode, mLaunchedFromUid);\n            }\n\n        }\n    }\n\n    void showAppDetails(ResolveInfo ri) {\n        Intent in = new Intent().setAction(\"android.settings.APPLICATION_DETAILS_SETTINGS\")\n                .setData(Uri.fromParts(\"package\", ri.activityInfo.packageName, null))\n                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);\n        startActivity(in);\n    }\n\n    static class ViewHolder {\n        public TextView text;\n        public TextView text2;\n        public ImageView icon;\n\n        public ViewHolder(View view) {\n            text = (TextView) view.findViewById(R.id.text1);\n            text2 = (TextView) view.findViewById(R.id.text2);\n            icon = (ImageView) view.findViewById(R.id.icon);\n        }\n    }\n\n    private final class DisplayResolveInfo {\n        ResolveInfo ri;\n        CharSequence displayLabel;\n        Drawable displayIcon;\n        CharSequence extendedInfo;\n        Intent origIntent;\n\n        DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,\n                           CharSequence pInfo, Intent pOrigIntent) {\n            ri = pri;\n            displayLabel = pLabel;\n            extendedInfo = pInfo;\n            origIntent = pOrigIntent;\n        }\n    }\n\n    private final class ResolveListAdapter extends BaseAdapter {\n        private final Intent[] mInitialIntents;\n        private final List<ResolveInfo> mBaseResolveList;\n        private final Intent mIntent;\n        private final int mLaunchedFromUid;\n        private final LayoutInflater mInflater;\n        List<DisplayResolveInfo> mList;\n        List<ResolveInfo> mOrigResolveList;\n        private ResolveInfo mLastChosen;\n        private int mInitialHighlight = -1;\n\n        public ResolveListAdapter(Context context, Intent intent,\n                                  Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {\n            mIntent = new Intent(intent);\n            mInitialIntents = initialIntents;\n            mBaseResolveList = rList;\n            mLaunchedFromUid = launchedFromUid;\n            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n            mList = new ArrayList<DisplayResolveInfo>();\n            rebuildList();\n        }\n\n        public void handlePackagesChanged() {\n            final int oldItemCount = getCount();\n            rebuildList();\n            notifyDataSetChanged();\n            final int newItemCount = getCount();\n            if (newItemCount == 0) {\n                // We no longer have any items...  just finish the activity.\n                finish();\n            }\n        }\n\n        public int getInitialHighlight() {\n            return mInitialHighlight;\n        }\n\n        private void rebuildList() {\n            List<ResolveInfo> currentResolveList;\n\n//            try {\n//                mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(\n//                        mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),\n//                        PackageManager.MATCH_DEFAULT_ONLY);\n//            } catch (RemoteException re) {\n//                Log.d(TAG, \"Error calling setLastChosenActivity\\n\" + re);\n//            }\n\n            mList.clear();\n            if (mBaseResolveList != null) {\n                currentResolveList = mBaseResolveList;\n                mOrigResolveList = null;\n            } else {\n                currentResolveList = mOrigResolveList = mPm.queryIntentActivities(\n                        mIntent, PackageManager.MATCH_DEFAULT_ONLY\n                                | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));\n                // Filter out any activities that the launched uid does not\n                // have permission for.  We don't do this when we have an explicit\n                // list of resolved activities, because that only happens when\n                // we are being subclassed, so we can safely launch whatever\n                // they gave us.\n//                if (currentResolveList != null) {\n//                    for (int i = currentResolveList.size() - 1; i >= 0; i--) {\n//                        ActivityInfo ai = currentResolveList.get(i).activityInfo;\n//                        int granted = ActivityManager.checkComponentPermission(\n//                                ai.permission, mLaunchedFromUid,\n//                                ai.applicationInfo.uid, ai.exported);\n//                        if (granted != PackageManager.PERMISSION_GRANTED) {\n//                            // Access not allowed!\n//                            if (mOrigResolveList == currentResolveList) {\n//                                mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);\n//                            }\n//                            currentResolveList.remove(i);\n//                        }\n//                    }\n//                }\n            }\n            int N;\n            if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {\n                // Only display the first matches that are either of equal\n                // priority or have asked to be default options.\n                ResolveInfo r0 = currentResolveList.get(0);\n                for (int i = 1; i < N; i++) {\n                    ResolveInfo ri = currentResolveList.get(i);\n                    if (DEBUG) VLog.v(\n                            \"ResolveListActivity\",\n                            r0.activityInfo.name + \"=\" +\n                                    r0.priority + \"/\" + r0.isDefault + \" vs \" +\n                                    ri.activityInfo.name + \"=\" +\n                                    ri.priority + \"/\" + ri.isDefault);\n                    if (r0.priority != ri.priority ||\n                            r0.isDefault != ri.isDefault) {\n                        while (i < N) {\n                            if (mOrigResolveList == currentResolveList) {\n                                mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);\n                            }\n                            currentResolveList.remove(i);\n                            N--;\n                        }\n                    }\n                }\n                if (N > 1) {\n                    ResolveInfo.DisplayNameComparator rComparator =\n                            new ResolveInfo.DisplayNameComparator(mPm);\n                    Collections.sort(currentResolveList, rComparator);\n                }\n                // First put the initial items at the top.\n                if (mInitialIntents != null) {\n                    for (int i = 0; i < mInitialIntents.length; i++) {\n                        Intent ii = mInitialIntents[i];\n                        if (ii == null) {\n                            continue;\n                        }\n                        ActivityInfo ai = ii.resolveActivityInfo(\n                                getPackageManager(), 0);\n                        if (ai == null) {\n                            VLog.w(\"ResolverActivity\", \"No activity found for \"\n                                    + ii);\n                            continue;\n                        }\n                        ResolveInfo ri = new ResolveInfo();\n                        ri.activityInfo = ai;\n                        if (ii instanceof LabeledIntent) {\n                            LabeledIntent li = (LabeledIntent) ii;\n                            ri.resolvePackageName = li.getSourcePackage();\n                            ri.labelRes = li.getLabelResource();\n                            ri.nonLocalizedLabel = li.getNonLocalizedLabel();\n                            ri.icon = li.getIconResource();\n                        }\n                        mList.add(new DisplayResolveInfo(ri,\n                                ri.loadLabel(getPackageManager()), null, ii));\n                    }\n                }\n\n                // Check for applications with same name and use application name or\n                // package name if necessary\n                r0 = currentResolveList.get(0);\n                int start = 0;\n                CharSequence r0Label = r0.loadLabel(mPm);\n                mShowExtended = false;\n                for (int i = 1; i < N; i++) {\n                    if (r0Label == null) {\n                        r0Label = r0.activityInfo.packageName;\n                    }\n                    ResolveInfo ri = currentResolveList.get(i);\n                    CharSequence riLabel = ri.loadLabel(mPm);\n                    if (riLabel == null) {\n                        riLabel = ri.activityInfo.packageName;\n                    }\n                    if (riLabel.equals(r0Label)) {\n                        continue;\n                    }\n                    processGroup(currentResolveList, start, (i - 1), r0, r0Label);\n                    r0 = ri;\n                    r0Label = riLabel;\n                    start = i;\n                }\n                // Process last group\n                processGroup(currentResolveList, start, (N - 1), r0, r0Label);\n            }\n        }\n\n        private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,\n                                  CharSequence roLabel) {\n            // Process labels from start to i\n            int num = end - start + 1;\n            if (num == 1) {\n                if (mLastChosen != null\n                        && mLastChosen.activityInfo.packageName.equals(\n                        ro.activityInfo.packageName)\n                        && mLastChosen.activityInfo.name.equals(ro.activityInfo.name)) {\n                    mInitialHighlight = mList.size();\n                }\n                // No duplicate labels. Use label for entry at start\n                mList.add(new DisplayResolveInfo(ro, roLabel, null, null));\n            } else {\n                mShowExtended = true;\n                boolean usePkg = false;\n                CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);\n                if (startApp == null) {\n                    usePkg = true;\n                }\n                if (!usePkg) {\n                    // Use HashSet to track duplicates\n                    HashSet<CharSequence> duplicates =\n                            new HashSet<CharSequence>();\n                    duplicates.add(startApp);\n                    for (int j = start + 1; j <= end; j++) {\n                        ResolveInfo jRi = rList.get(j);\n                        CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);\n                        if ((jApp == null) || (duplicates.contains(jApp))) {\n                            usePkg = true;\n                            break;\n                        } else {\n                            duplicates.add(jApp);\n                        }\n                    }\n                    // Clear HashSet for later use\n                    duplicates.clear();\n                }\n                for (int k = start; k <= end; k++) {\n                    ResolveInfo add = rList.get(k);\n                    if (mLastChosen != null\n                            && mLastChosen.activityInfo.packageName.equals(\n                            add.activityInfo.packageName)\n                            && mLastChosen.activityInfo.name.equals(add.activityInfo.name)) {\n                        mInitialHighlight = mList.size();\n                    }\n                    if (usePkg) {\n                        // Use application name for all entries from start to end-1\n                        mList.add(new DisplayResolveInfo(add, roLabel,\n                                add.activityInfo.packageName, null));\n                    } else {\n                        // Use package name for all entries from start to end-1\n                        mList.add(new DisplayResolveInfo(add, roLabel,\n                                add.activityInfo.applicationInfo.loadLabel(mPm), null));\n                    }\n                }\n            }\n        }\n\n        public ResolveInfo resolveInfoForPosition(int position) {\n            return mList.get(position).ri;\n        }\n\n        public Intent intentForPosition(int position) {\n            DisplayResolveInfo dri = mList.get(position);\n\n            Intent intent = new Intent(dri.origIntent != null\n                    ? dri.origIntent : mIntent);\n            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT\n                    | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);\n            ActivityInfo ai = dri.ri.activityInfo;\n            intent.setComponent(new ComponentName(\n                    ai.applicationInfo.packageName, ai.name));\n            return intent;\n        }\n\n        public int getCount() {\n            return mList.size();\n        }\n\n        public Object getItem(int position) {\n            return mList.get(position);\n        }\n\n        public long getItemId(int position) {\n            return position;\n        }\n\n        public View getView(int position, View convertView, ViewGroup parent) {\n            View view;\n            if (convertView == null) {\n                view = mInflater.inflate(R.layout.resolve_list_item, parent, false);\n\n                final ViewHolder holder = new ViewHolder(view);\n                view.setTag(holder);\n\n                // Fix the icon size even if we have different sized resources\n                ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();\n                lp.width = lp.height = mIconSize;\n            } else {\n                view = convertView;\n            }\n            bindView(view, mList.get(position));\n            return view;\n        }\n\n        private final void bindView(View view, DisplayResolveInfo info) {\n            final ViewHolder holder = (ViewHolder) view.getTag();\n            holder.text.setText(info.displayLabel);\n            if (mShowExtended) {\n                holder.text2.setVisibility(View.VISIBLE);\n                holder.text2.setText(info.extendedInfo);\n            } else {\n                holder.text2.setVisibility(View.GONE);\n            }\n            if (info.displayIcon == null) {\n                new LoadIconTask().execute(info);\n            }\n            holder.icon.setImageDrawable(info.displayIcon);\n        }\n    }\n\n    class ItemLongClickListener implements AdapterView.OnItemLongClickListener {\n\n        @Override\n        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {\n            ResolveInfo ri = mAdapter.resolveInfoForPosition(position);\n            showAppDetails(ri);\n            return true;\n        }\n\n    }\n\n    class LoadIconTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {\n        @Override\n        protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {\n            final DisplayResolveInfo info = params[0];\n            if (info.displayIcon == null) {\n                info.displayIcon = loadIconForResolveInfo(info.ri);\n            }\n            return info;\n        }\n\n        @Override\n        protected void onPostExecute(DisplayResolveInfo info) {\n            mAdapter.notifyDataSetChanged();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/ShortcutHandleActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.app.Activity;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.ipc.VActivityManager;\n\nimport java.net.URISyntaxException;\n\n/**\n * @author Lody\n */\npublic class ShortcutHandleActivity extends Activity {\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        finish();\n        Intent intent = getIntent();\n        if (intent == null) {\n            return;\n        }\n        int userId = intent.getIntExtra(\"_VA_|_user_id_\", 0);\n        String splashUri = intent.getStringExtra(\"_VA_|_splash_\");\n        String targetUri = intent.getStringExtra(\"_VA_|_uri_\");\n        Intent splashIntent = null;\n        Intent targetIntent = null;\n        if (splashUri != null) {\n            try {\n                splashIntent = Intent.parseUri(splashUri, 0);\n            } catch (URISyntaxException e) {\n                e.printStackTrace();\n            }\n        }\n        if (targetUri != null) {\n            try {\n                targetIntent = Intent.parseUri(targetUri, 0);\n            } catch (URISyntaxException e) {\n                e.printStackTrace();\n            }\n        }\n        if (targetIntent == null) {\n            return;\n        }\n\n        Bundle extras = intent.getExtras();\n        if (extras != null) {\n            Bundle targetBundle = new Bundle(extras);\n            for (String key : extras.keySet()) {\n                if (key.startsWith(\"_VA_\")) {\n                    targetBundle.remove(key);\n                }\n            }\n            targetIntent.putExtras(targetBundle);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n            targetIntent.setSelector(null);\n        }\n\n        if (splashIntent == null) {\n            try {\n                VActivityManager.get().startActivity(targetIntent, userId);\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        } else {\n            splashIntent.putExtra(Constants.PASS_KEY_INTENT, targetIntent);\n            splashIntent.putExtra(Constants.PASS_KEY_USER, userId);\n            String pkg = targetIntent.getPackage();\n            if (pkg == null) {\n                ComponentName component = targetIntent.getComponent();\n                if (component != null) {\n                    pkg = component.getPackageName();\n                }\n            }\n            splashIntent.putExtra(Constants.PASS_PKG_NAME_ARGUMENT, pkg);\n            startActivity(splashIntent);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.InvocationStubManager;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.hook.proxies.am.HCallbackStub;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.StubActivityRecord;\n\n/**\n * @author Lody\n *\n */\npublic abstract class StubActivity extends Activity {\n\n\t@Override\n\tprotected void onCreate(Bundle savedInstanceState) {\n\t\t// The savedInstanceState's classLoader is not exist.\n\t\tsuper.onCreate(null);\n\t\tfinish();\n        // It seems that we have conflict with the other Android-Plugin-Framework.\n\t\tIntent stubIntent = getIntent();\n        // Try to acquire the actually component information.\n\t\tStubActivityRecord r = new StubActivityRecord(stubIntent);\n\t\tif (r.intent != null) {\n\t\t\tif (TextUtils.equals(r.info.processName, VirtualRuntime.getProcessName()) && r.userId == VUserHandle.myUserId()) {\n                // Retry to inject the HCallback to instead of the exist one.\n\t\t\t\tInvocationStubManager.getInstance().checkEnv(HCallbackStub.class);\n\t\t\t\tIntent intent = r.intent;\n\t\t\t\tintent.setExtrasClassLoader(VClientImpl.get().getCurrentApplication().getClassLoader());\n\t\t\t\tstartActivity(intent);\n\t\t\t} else {\n                // Start the target Activity in other process.\n\t\t\t\tVActivityManager.get().startActivity(r.intent, r.userId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static class C0 extends StubActivity {\n\t}\n\n\tpublic static class C1 extends StubActivity {\n\t}\n\n\tpublic static class C2 extends StubActivity {\n\t}\n\n\tpublic static class C3 extends StubActivity {\n\t}\n\n\tpublic static class C4 extends StubActivity {\n\t}\n\n\tpublic static class C5 extends StubActivity {\n\t}\n\n\tpublic static class C6 extends StubActivity {\n\t}\n\n\tpublic static class C7 extends StubActivity {\n\t}\n\n\tpublic static class C8 extends StubActivity {\n\t}\n\n\tpublic static class C9 extends StubActivity {\n\t}\n\n\tpublic static class C10 extends StubActivity {\n\t}\n\n\tpublic static class C11 extends StubActivity {\n\t}\n\n\tpublic static class C12 extends StubActivity {\n\t}\n\n\tpublic static class C13 extends StubActivity {\n\t}\n\n\tpublic static class C14 extends StubActivity {\n\t}\n\n\tpublic static class C15 extends StubActivity {\n\t}\n\n\tpublic static class C16 extends StubActivity {\n\t}\n\n\tpublic static class C17 extends StubActivity {\n\t}\n\n\tpublic static class C18 extends StubActivity {\n\t}\n\n\tpublic static class C19 extends StubActivity {\n\t}\n\n\tpublic static class C20 extends StubActivity {\n\t}\n\n\tpublic static class C21 extends StubActivity {\n\t}\n\n\tpublic static class C22 extends StubActivity {\n\t}\n\n\tpublic static class C23 extends StubActivity {\n\t}\n\n\tpublic static class C24 extends StubActivity {\n\t}\n\n\tpublic static class C25 extends StubActivity {\n\t}\n\n\tpublic static class C26 extends StubActivity {\n\t}\n\n\tpublic static class C27 extends StubActivity {\n\t}\n\n\tpublic static class C28 extends StubActivity {\n\t}\n\n\tpublic static class C29 extends StubActivity {\n\t}\n\n\tpublic static class C30 extends StubActivity {\n\t}\n\n\tpublic static class C31 extends StubActivity {\n\t}\n\n\tpublic static class C32 extends StubActivity {\n\t}\n\n\tpublic static class C33 extends StubActivity {\n\t}\n\n\tpublic static class C34 extends StubActivity {\n\t}\n\n\tpublic static class C35 extends StubActivity {\n\t}\n\n\tpublic static class C36 extends StubActivity {\n\t}\n\n\tpublic static class C37 extends StubActivity {\n\t}\n\n\tpublic static class C38 extends StubActivity {\n\t}\n\n\tpublic static class C39 extends StubActivity {\n\t}\n\n\tpublic static class C40 extends StubActivity {\n\t}\n\n\tpublic static class C41 extends StubActivity {\n\t}\n\n\tpublic static class C42 extends StubActivity {\n\t}\n\n\tpublic static class C43 extends StubActivity {\n\t}\n\n\tpublic static class C44 extends StubActivity {\n\t}\n\n\tpublic static class C45 extends StubActivity {\n\t}\n\n\tpublic static class C46 extends StubActivity {\n\t}\n\n\tpublic static class C47 extends StubActivity {\n\t}\n\n\tpublic static class C48 extends StubActivity {\n\t}\n\n\tpublic static class C49 extends StubActivity {\n\t}\n\n\tpublic static class C50 extends StubActivity {\n\t}\n\n\tpublic static class C51 extends StubActivity {\n\t}\n\n\tpublic static class C52 extends StubActivity {\n\t}\n\n\tpublic static class C53 extends StubActivity {\n\t}\n\n\tpublic static class C54 extends StubActivity {\n\t}\n\n\tpublic static class C55 extends StubActivity {\n\t}\n\n\tpublic static class C56 extends StubActivity {\n\t}\n\n\tpublic static class C57 extends StubActivity {\n\t}\n\n\tpublic static class C58 extends StubActivity {\n\t}\n\n\tpublic static class C59 extends StubActivity {\n\t}\n\n\tpublic static class C60 extends StubActivity {\n\t}\n\n\tpublic static class C61 extends StubActivity {\n\t}\n\n\tpublic static class C62 extends StubActivity {\n\t}\n\n\tpublic static class C63 extends StubActivity {\n\t}\n\n\tpublic static class C64 extends StubActivity {\n\t}\n\n\tpublic static class C65 extends StubActivity {\n\t}\n\n\tpublic static class C66 extends StubActivity {\n\t}\n\n\tpublic static class C67 extends StubActivity {\n\t}\n\n\tpublic static class C68 extends StubActivity {\n\t}\n\n\tpublic static class C69 extends StubActivity {\n\t}\n\n\tpublic static class C70 extends StubActivity {\n\t}\n\n\tpublic static class C71 extends StubActivity {\n\t}\n\n\tpublic static class C72 extends StubActivity {\n\t}\n\n\tpublic static class C73 extends StubActivity {\n\t}\n\n\tpublic static class C74 extends StubActivity {\n\t}\n\n\tpublic static class C75 extends StubActivity {\n\t}\n\n\tpublic static class C76 extends StubActivity {\n\t}\n\n\tpublic static class C77 extends StubActivity {\n\t}\n\n\tpublic static class C78 extends StubActivity {\n\t}\n\n\tpublic static class C79 extends StubActivity {\n\t}\n\n\tpublic static class C80 extends StubActivity {\n\t}\n\n\tpublic static class C81 extends StubActivity {\n\t}\n\n\tpublic static class C82 extends StubActivity {\n\t}\n\n\tpublic static class C83 extends StubActivity {\n\t}\n\n\tpublic static class C84 extends StubActivity {\n\t}\n\n\tpublic static class C85 extends StubActivity {\n\t}\n\n\tpublic static class C86 extends StubActivity {\n\t}\n\n\tpublic static class C87 extends StubActivity {\n\t}\n\n\tpublic static class C88 extends StubActivity {\n\t}\n\n\tpublic static class C89 extends StubActivity {\n\t}\n\n\tpublic static class C90 extends StubActivity {\n\t}\n\n\tpublic static class C91 extends StubActivity {\n\t}\n\n\tpublic static class C92 extends StubActivity {\n\t}\n\n\tpublic static class C93 extends StubActivity {\n\t}\n\n\tpublic static class C94 extends StubActivity {\n\t}\n\n\tpublic static class C95 extends StubActivity {\n\t}\n\n\tpublic static class C96 extends StubActivity {\n\t}\n\n\tpublic static class C97 extends StubActivity {\n\t}\n\n\tpublic static class C98 extends StubActivity {\n\t}\n\n\tpublic static class C99 extends StubActivity {\n\t}\n\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubCP.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.ConditionVariable;\nimport android.os.IBinder;\nimport android.os.Process;\n\nimport com.lody.virtual.client.VClientImpl;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.compat.BundleCompat;\n\n/**\n * @author Lody\n *\n */\npublic class StubCP extends ContentProvider {\n\n\t@Override\n\tpublic boolean onCreate() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Bundle call(String method, String arg, Bundle extras) {\n\t\tif (\"_VA_|_init_process_\".equals(method)) {\n\t\t\treturn initProcess(extras);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Bundle initProcess(Bundle extras) {\n\t\tConditionVariable lock = VirtualCore.get().getInitLock();\n\t\tif (lock != null) {\n\t\t\tlock.block();\n\t\t}\n\t\tIBinder token = BundleCompat.getBinder(extras,\"_VA_|_binder_\");\n\t\tint vuid = extras.getInt(\"_VA_|_vuid_\");\n\t\tVClientImpl client = VClientImpl.get();\n\t\tclient.initProcess(token, vuid);\n\t\tBundle res = new Bundle();\n\t\tBundleCompat.putBinder(res, \"_VA_|_client_\", client.asBinder());\n\t\tres.putInt(\"_VA_|_pid_\", Process.myPid());\n\t\treturn res;\n\t}\n\n\t@Override\n\tpublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic String getType(Uri uri) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Uri insert(Uri uri, ContentValues values) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic int delete(Uri uri, String selection, String[] selectionArgs) {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n\t\treturn 0;\n\t}\n\n\n\tpublic static class C0 extends StubCP {\n\t}\n\n\tpublic static class C1 extends StubCP {\n\t}\n\n\tpublic static class C2 extends StubCP {\n\t}\n\n\tpublic static class C3 extends StubCP {\n\t}\n\n\tpublic static class C4 extends StubCP {\n\t}\n\n\tpublic static class C5 extends StubCP {\n\t}\n\n\tpublic static class C6 extends StubCP {\n\t}\n\n\tpublic static class C7 extends StubCP {\n\t}\n\n\tpublic static class C8 extends StubCP {\n\t}\n\n\tpublic static class C9 extends StubCP {\n\t}\n\n\tpublic static class C10 extends StubCP {\n\t}\n\n\tpublic static class C11 extends StubCP {\n\t}\n\n\tpublic static class C12 extends StubCP {\n\t}\n\n\tpublic static class C13 extends StubCP {\n\t}\n\n\tpublic static class C14 extends StubCP {\n\t}\n\n\tpublic static class C15 extends StubCP {\n\t}\n\n\tpublic static class C16 extends StubCP {\n\t}\n\n\tpublic static class C17 extends StubCP {\n\t}\n\n\tpublic static class C18 extends StubCP {\n\t}\n\n\tpublic static class C19 extends StubCP {\n\t}\n\n\tpublic static class C20 extends StubCP {\n\t}\n\n\tpublic static class C21 extends StubCP {\n\t}\n\n\tpublic static class C22 extends StubCP {\n\t}\n\n\tpublic static class C23 extends StubCP {\n\t}\n\n\tpublic static class C24 extends StubCP {\n\t}\n\n\tpublic static class C25 extends StubCP {\n\t}\n\n\tpublic static class C26 extends StubCP {\n\t}\n\n\tpublic static class C27 extends StubCP {\n\t}\n\n\tpublic static class C28 extends StubCP {\n\t}\n\n\tpublic static class C29 extends StubCP {\n\t}\n\n\tpublic static class C30 extends StubCP {\n\t}\n\n\tpublic static class C31 extends StubCP {\n\t}\n\n\tpublic static class C32 extends StubCP {\n\t}\n\n\tpublic static class C33 extends StubCP {\n\t}\n\n\tpublic static class C34 extends StubCP {\n\t}\n\n\tpublic static class C35 extends StubCP {\n\t}\n\n\tpublic static class C36 extends StubCP {\n\t}\n\n\tpublic static class C37 extends StubCP {\n\t}\n\n\tpublic static class C38 extends StubCP {\n\t}\n\n\tpublic static class C39 extends StubCP {\n\t}\n\n\tpublic static class C40 extends StubCP {\n\t}\n\n\tpublic static class C41 extends StubCP {\n\t}\n\n\tpublic static class C42 extends StubCP {\n\t}\n\n\tpublic static class C43 extends StubCP {\n\t}\n\n\tpublic static class C44 extends StubCP {\n\t}\n\n\tpublic static class C45 extends StubCP {\n\t}\n\n\tpublic static class C46 extends StubCP {\n\t}\n\n\tpublic static class C47 extends StubCP {\n\t}\n\n\tpublic static class C48 extends StubCP {\n\t}\n\n\tpublic static class C49 extends StubCP {\n\t}\n\n\tpublic static class C50 extends StubCP {\n\t}\n\n\tpublic static class C51 extends StubCP {\n\t}\n\n\tpublic static class C52 extends StubCP {\n\t}\n\n\tpublic static class C53 extends StubCP {\n\t}\n\n\tpublic static class C54 extends StubCP {\n\t}\n\n\tpublic static class C55 extends StubCP {\n\t}\n\n\tpublic static class C56 extends StubCP {\n\t}\n\n\tpublic static class C57 extends StubCP {\n\t}\n\n\tpublic static class C58 extends StubCP {\n\t}\n\n\tpublic static class C59 extends StubCP {\n\t}\n\n\tpublic static class C60 extends StubCP {\n\t}\n\n\tpublic static class C61 extends StubCP {\n\t}\n\n\tpublic static class C62 extends StubCP {\n\t}\n\n\tpublic static class C63 extends StubCP {\n\t}\n\n\tpublic static class C64 extends StubCP {\n\t}\n\n\tpublic static class C65 extends StubCP {\n\t}\n\n\tpublic static class C66 extends StubCP {\n\t}\n\n\tpublic static class C67 extends StubCP {\n\t}\n\n\tpublic static class C68 extends StubCP {\n\t}\n\n\tpublic static class C69 extends StubCP {\n\t}\n\n\tpublic static class C70 extends StubCP {\n\t}\n\n\tpublic static class C71 extends StubCP {\n\t}\n\n\tpublic static class C72 extends StubCP {\n\t}\n\n\tpublic static class C73 extends StubCP {\n\t}\n\n\tpublic static class C74 extends StubCP {\n\t}\n\n\tpublic static class C75 extends StubCP {\n\t}\n\n\tpublic static class C76 extends StubCP {\n\t}\n\n\tpublic static class C77 extends StubCP {\n\t}\n\n\tpublic static class C78 extends StubCP {\n\t}\n\n\tpublic static class C79 extends StubCP {\n\t}\n\n\tpublic static class C80 extends StubCP {\n\t}\n\n\tpublic static class C81 extends StubCP {\n\t}\n\n\tpublic static class C82 extends StubCP {\n\t}\n\n\tpublic static class C83 extends StubCP {\n\t}\n\n\tpublic static class C84 extends StubCP {\n\t}\n\n\tpublic static class C85 extends StubCP {\n\t}\n\n\tpublic static class C86 extends StubCP {\n\t}\n\n\tpublic static class C87 extends StubCP {\n\t}\n\n\tpublic static class C88 extends StubCP {\n\t}\n\n\tpublic static class C89 extends StubCP {\n\t}\n\n\tpublic static class C90 extends StubCP {\n\t}\n\n\tpublic static class C91 extends StubCP {\n\t}\n\n\tpublic static class C92 extends StubCP {\n\t}\n\n\tpublic static class C93 extends StubCP {\n\t}\n\n\tpublic static class C94 extends StubCP {\n\t}\n\n\tpublic static class C95 extends StubCP {\n\t}\n\n\tpublic static class C96 extends StubCP {\n\t}\n\n\tpublic static class C97 extends StubCP {\n\t}\n\n\tpublic static class C98 extends StubCP {\n\t}\n\n\tpublic static class C99 extends StubCP {\n\t}\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubDialog.java",
    "content": "package com.lody.virtual.client.stub;\n\n/**\n * @author Lody\n *\n */\npublic abstract class StubDialog extends StubActivity {\n\n\n\tpublic static class C0 extends StubDialog {\n\t}\n\n\tpublic static class C1 extends StubDialog {\n\t}\n\n\tpublic static class C2 extends StubDialog {\n\t}\n\n\tpublic static class C3 extends StubDialog {\n\t}\n\n\tpublic static class C4 extends StubDialog {\n\t}\n\n\tpublic static class C5 extends StubDialog {\n\t}\n\n\tpublic static class C6 extends StubDialog {\n\t}\n\n\tpublic static class C7 extends StubDialog {\n\t}\n\n\tpublic static class C8 extends StubDialog {\n\t}\n\n\tpublic static class C9 extends StubDialog {\n\t}\n\n\tpublic static class C10 extends StubDialog {\n\t}\n\n\tpublic static class C11 extends StubDialog {\n\t}\n\n\tpublic static class C12 extends StubDialog {\n\t}\n\n\tpublic static class C13 extends StubDialog {\n\t}\n\n\tpublic static class C14 extends StubDialog {\n\t}\n\n\tpublic static class C15 extends StubDialog {\n\t}\n\n\tpublic static class C16 extends StubDialog {\n\t}\n\n\tpublic static class C17 extends StubDialog {\n\t}\n\n\tpublic static class C18 extends StubDialog {\n\t}\n\n\tpublic static class C19 extends StubDialog {\n\t}\n\n\tpublic static class C20 extends StubDialog {\n\t}\n\n\tpublic static class C21 extends StubDialog {\n\t}\n\n\tpublic static class C22 extends StubDialog {\n\t}\n\n\tpublic static class C23 extends StubDialog {\n\t}\n\n\tpublic static class C24 extends StubDialog {\n\t}\n\n\tpublic static class C25 extends StubDialog {\n\t}\n\n\tpublic static class C26 extends StubDialog {\n\t}\n\n\tpublic static class C27 extends StubDialog {\n\t}\n\n\tpublic static class C28 extends StubDialog {\n\t}\n\n\tpublic static class C29 extends StubDialog {\n\t}\n\n\tpublic static class C30 extends StubDialog {\n\t}\n\n\tpublic static class C31 extends StubDialog {\n\t}\n\n\tpublic static class C32 extends StubDialog {\n\t}\n\n\tpublic static class C33 extends StubDialog {\n\t}\n\n\tpublic static class C34 extends StubDialog {\n\t}\n\n\tpublic static class C35 extends StubDialog {\n\t}\n\n\tpublic static class C36 extends StubDialog {\n\t}\n\n\tpublic static class C37 extends StubDialog {\n\t}\n\n\tpublic static class C38 extends StubDialog {\n\t}\n\n\tpublic static class C39 extends StubDialog {\n\t}\n\n\tpublic static class C40 extends StubDialog {\n\t}\n\n\tpublic static class C41 extends StubDialog {\n\t}\n\n\tpublic static class C42 extends StubDialog {\n\t}\n\n\tpublic static class C43 extends StubDialog {\n\t}\n\n\tpublic static class C44 extends StubDialog {\n\t}\n\n\tpublic static class C45 extends StubDialog {\n\t}\n\n\tpublic static class C46 extends StubDialog {\n\t}\n\n\tpublic static class C47 extends StubDialog {\n\t}\n\n\tpublic static class C48 extends StubDialog {\n\t}\n\n\tpublic static class C49 extends StubDialog {\n\t}\n\n\tpublic static class C50 extends StubDialog {\n\t}\n\n\tpublic static class C51 extends StubDialog {\n\t}\n\n\tpublic static class C52 extends StubDialog {\n\t}\n\n\tpublic static class C53 extends StubDialog {\n\t}\n\n\tpublic static class C54 extends StubDialog {\n\t}\n\n\tpublic static class C55 extends StubDialog {\n\t}\n\n\tpublic static class C56 extends StubDialog {\n\t}\n\n\tpublic static class C57 extends StubDialog {\n\t}\n\n\tpublic static class C58 extends StubDialog {\n\t}\n\n\tpublic static class C59 extends StubDialog {\n\t}\n\n\tpublic static class C60 extends StubDialog {\n\t}\n\n\tpublic static class C61 extends StubDialog {\n\t}\n\n\tpublic static class C62 extends StubDialog {\n\t}\n\n\tpublic static class C63 extends StubDialog {\n\t}\n\n\tpublic static class C64 extends StubDialog {\n\t}\n\n\tpublic static class C65 extends StubDialog {\n\t}\n\n\tpublic static class C66 extends StubDialog {\n\t}\n\n\tpublic static class C67 extends StubDialog {\n\t}\n\n\tpublic static class C68 extends StubDialog {\n\t}\n\n\tpublic static class C69 extends StubDialog {\n\t}\n\n\tpublic static class C70 extends StubDialog {\n\t}\n\n\tpublic static class C71 extends StubDialog {\n\t}\n\n\tpublic static class C72 extends StubDialog {\n\t}\n\n\tpublic static class C73 extends StubDialog {\n\t}\n\n\tpublic static class C74 extends StubDialog {\n\t}\n\n\tpublic static class C75 extends StubDialog {\n\t}\n\n\tpublic static class C76 extends StubDialog {\n\t}\n\n\tpublic static class C77 extends StubDialog {\n\t}\n\n\tpublic static class C78 extends StubDialog {\n\t}\n\n\tpublic static class C79 extends StubDialog {\n\t}\n\n\tpublic static class C80 extends StubDialog {\n\t}\n\n\tpublic static class C81 extends StubDialog {\n\t}\n\n\tpublic static class C82 extends StubDialog {\n\t}\n\n\tpublic static class C83 extends StubDialog {\n\t}\n\n\tpublic static class C84 extends StubDialog {\n\t}\n\n\tpublic static class C85 extends StubDialog {\n\t}\n\n\tpublic static class C86 extends StubDialog {\n\t}\n\n\tpublic static class C87 extends StubDialog {\n\t}\n\n\tpublic static class C88 extends StubDialog {\n\t}\n\n\tpublic static class C89 extends StubDialog {\n\t}\n\n\tpublic static class C90 extends StubDialog {\n\t}\n\n\tpublic static class C91 extends StubDialog {\n\t}\n\n\tpublic static class C92 extends StubDialog {\n\t}\n\n\tpublic static class C93 extends StubDialog {\n\t}\n\n\tpublic static class C94 extends StubDialog {\n\t}\n\n\tpublic static class C95 extends StubDialog {\n\t}\n\n\tpublic static class C96 extends StubDialog {\n\t}\n\n\tpublic static class C97 extends StubDialog {\n\t}\n\n\tpublic static class C98 extends StubDialog {\n\t}\n\n\tpublic static class C99 extends StubDialog {\n\t}\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubExcludeFromRecentActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\n/**\n * deal with Activity manifest property excludeFromRecents\n * deal with the bug : Mobile Legends has two recent task\n * added by xiawanli,  2018.9.6\n */\npublic abstract class StubExcludeFromRecentActivity extends StubActivity {\n\n    public static class C0 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C1 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C2 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C3 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C4 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C5 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C6 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C7 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C8 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C9 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C10 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C11 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C12 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C13 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C14 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C15 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C16 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C17 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C18 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C19 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C20 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C21 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C22 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C23 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C24 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C25 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C26 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C27 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C28 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C29 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C30 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C31 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C32 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C33 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C34 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C35 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C36 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C37 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C38 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C39 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C40 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C41 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C42 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C43 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C44 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C45 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C46 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C47 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C48 extends StubExcludeFromRecentActivity {\n    }\n\n    public static class C49 extends StubExcludeFromRecentActivity {\n    }\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubJob.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.annotation.TargetApi;\nimport android.app.Service;\nimport android.app.job.IJobCallback;\nimport android.app.job.IJobService;\nimport android.app.job.JobParameters;\nimport android.app.job.JobScheduler;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.InvocationStubManager;\nimport com.lody.virtual.client.hook.proxies.am.ActivityManagerStub;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.helper.collection.SparseArray;\nimport com.lody.virtual.os.VUserHandle;\n\nimport java.util.Map;\n\nimport static com.lody.virtual.server.job.VJobSchedulerService.JobConfig;\nimport static com.lody.virtual.server.job.VJobSchedulerService.JobId;\nimport static com.lody.virtual.server.job.VJobSchedulerService.get;\n\n/**\n * @author Lody\n *         <p>\n *         This service running on the Server process.\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class StubJob extends Service {\n\n    private static final String TAG = StubJob.class.getSimpleName();\n    private final SparseArray<JobSession> mJobSessions = new SparseArray<>();\n    private JobScheduler mScheduler;\n    private final IJobService mService = new IJobService.Stub() {\n\n        @Override\n        public void startJob(JobParameters jobParams) throws RemoteException {\n            int jobId = jobParams.getJobId();\n            IBinder binder = mirror.android.app.job.JobParameters.callback.get(jobParams);\n            IJobCallback callback = IJobCallback.Stub.asInterface(binder);\n            Map.Entry<JobId, JobConfig> entry = get().findJobByVirtualJobId(jobId);\n            if (entry == null) {\n                emptyCallback(callback, jobId);\n                mScheduler.cancel(jobId);\n            } else {\n                JobId key = entry.getKey();\n                JobConfig config = entry.getValue();\n                synchronized (mJobSessions) {\n                    JobSession session = mJobSessions.get(jobId);\n                    if (session != null) {\n                        // Job Session has exist.\n                        emptyCallback(callback, jobId);\n                    } else {\n                        session = new JobSession(jobId, callback, jobParams);\n                        mirror.android.app.job.JobParameters.callback.set(jobParams, session.asBinder());\n                        mirror.android.app.job.JobParameters.jobId.set(jobParams, key.clientJobId);\n                        Intent service = new Intent();\n                        service.setComponent(new ComponentName(key.packageName, config.serviceName));\n                        service.putExtra(\"_VA_|_user_id_\", VUserHandle.getUserId(key.vuid));\n                        boolean bound = false;\n                        try {\n                            bound = bindService(service, session, 0);\n                        } catch (Throwable e) {\n                            VLog.e(TAG, e);\n                        }\n                        if (bound) {\n                            mJobSessions.put(jobId, session);\n                        } else {\n                            emptyCallback(callback, jobId);\n                            mScheduler.cancel(jobId);\n                            get().cancel(jobId);\n                        }\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void stopJob(JobParameters jobParams) throws RemoteException {\n            int jobId = jobParams.getJobId();\n            synchronized (mJobSessions) {\n                JobSession session = mJobSessions.get(jobId);\n                if (session != null) {\n                    session.stopSession();\n                }\n            }\n        }\n    };\n\n    /**\n     * Make JobScheduler happy.\n     */\n    private void emptyCallback(IJobCallback callback, int jobId) {\n        try {\n            callback.acknowledgeStartMessage(jobId, false);\n            callback.jobFinished(jobId, false);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        InvocationStubManager.getInstance().checkEnv(ActivityManagerStub.class);\n        mScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return mService.asBinder();\n    }\n\n    private final class JobSession extends IJobCallback.Stub implements ServiceConnection {\n\n        private int jobId;\n        private IJobCallback clientCallback;\n        private JobParameters jobParams;\n        private IJobService clientJobService;\n\n        JobSession(int jobId, IJobCallback clientCallback, JobParameters jobParams) {\n            this.jobId = jobId;\n            this.clientCallback = clientCallback;\n            this.jobParams = jobParams;\n        }\n\n        @Override\n        public void acknowledgeStartMessage(int jobId, boolean ongoing) throws RemoteException {\n            clientCallback.acknowledgeStartMessage(jobId, ongoing);\n        }\n\n        @Override\n        public void acknowledgeStopMessage(int jobId, boolean reschedule) throws RemoteException {\n            clientCallback.acknowledgeStopMessage(jobId, reschedule);\n        }\n\n        @Override\n        public void jobFinished(int jobId, boolean reschedule) throws RemoteException {\n            clientCallback.jobFinished(jobId, reschedule);\n        }\n\n        @Override\n        public void onServiceConnected(ComponentName name, IBinder service) {\n            clientJobService = IJobService.Stub.asInterface(service);\n            if (clientJobService == null) {\n                emptyCallback(clientCallback, jobId);\n                stopSession();\n                return;\n            }\n            try {\n                clientJobService.startJob(jobParams);\n            } catch (RemoteException e) {\n                forceFinishJob();\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName name) {\n\n        }\n\n        void forceFinishJob() {\n            try {\n                clientCallback.jobFinished(jobId, false);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            } finally {\n                stopSession();\n            }\n        }\n\n        void stopSession() {\n            if (clientJobService != null) {\n                try {\n                    clientJobService.stopJob(jobParams);\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n            mJobSessions.remove(jobId);\n            unbindService(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubPendingActivity.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.remote.StubActivityRecord;\n\n/**\n * @author Lody\n */\n\npublic class StubPendingActivity extends Activity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        finish();\n        Intent intent = getIntent();\n        StubActivityRecord r = new StubActivityRecord(intent);\n        if (r.intent == null) {\n            return;\n        }\n        r.intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);\n        VActivityManager.get().startActivity(r.intent, r.userId);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubPendingReceiver.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.os.VUserHandle;\n\n/**\n * @author Lody\n */\n\npublic class StubPendingReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n                Intent realIntent = intent.getParcelableExtra(\"_VA_|_intent_\");\n        int userId = intent.getIntExtra(\"_VA_|_user_id_\", VUserHandle.USER_ALL);\n        if (realIntent != null) {\n            Intent newIntent = ComponentUtils.redirectBroadcastIntent(realIntent, userId);\n            if (newIntent != null) {\n                context.sendBroadcast(newIntent);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/StubPendingService.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport com.lody.virtual.client.ipc.VActivityManager;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\n\n/**\n * @author Lody\n */\n\npublic class StubPendingService extends Service {\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        // _VA_|_from_inner_ marked\n        if (intent != null) {\n            Intent realIntent = intent.getParcelableExtra(\"_VA_|_intent_\");\n            int userId = intent.getIntExtra(\"_VA_|_user_id_\", 0);\n            if (realIntent != null) {\n                VActivityManager.get().startService(null, realIntent, null, userId);\n            }\n        }\n        stopSelf();\n        return START_NOT_STICKY;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/client/stub/VASettings.java",
    "content": "package com.lody.virtual.client.stub;\n\nimport java.util.Locale;\n\n/**\n * @author Lody\n */\n\npublic class VASettings {\n    public static final String STUB_DEF_AUTHORITY = \"virtual_stub_\";\n    public static final String ACTION_BADGER_CHANGE = \"com.lody.virtual.BADGER_CHANGE\";\n    public static String STUB_ACTIVITY = StubActivity.class.getName();\n    public static String STUB_DIALOG = StubDialog.class.getName();\n    public static String STUB_CP = StubCP.class.getName();\n    public static String STUB_JOB = StubJob.class.getName();\n    public static String RESOLVER_ACTIVITY = ResolverActivity.class.getName();\n    public static String STUB_EXCLUDE_FROM_RECENT_ACTIVITY = StubExcludeFromRecentActivity.class.getName();\n    public static String STUB_CP_AUTHORITY = \"virtual_stub_\";\n    public static int STUB_COUNT = 50;\n    public static String[] PRIVILEGE_APPS = new String[]{\n            \"com.google.android.gms\"\n    };\n\n    /**\n     * If enable,\n     * App run in VA will allowed to create shortcut on your Desktop.\n     */\n    public static boolean ENABLE_INNER_SHORTCUT = true;\n\n    /**\n     * If enable,\n     * For example:\n     * when app access '/data/data/{Package Name}' or '/data/user/0/{Package Name}',\n     * we redirect it to '/data/data/{Your Host Package Name}/virtual/user/0/{Package Name}'.\n     */\n    public static boolean ENABLE_IO_REDIRECT = true;\n\n    public static String getStubExcludeFromRecentActivityName(int index) {\n        return String.format(Locale.ENGLISH, \"%s$C%d\", STUB_EXCLUDE_FROM_RECENT_ACTIVITY, index);\n    }\n\n    public static String getStubActivityName(int index) {\n        return String.format(Locale.ENGLISH, \"%s$C%d\", STUB_ACTIVITY, index);\n    }\n\n    public static String getStubDialogName(int index) {\n        return String.format(Locale.ENGLISH, \"%s$C%d\", STUB_DIALOG, index);\n    }\n\n    public static String getStubCP(int index) {\n        return String.format(Locale.ENGLISH, \"%s$C%d\", STUB_CP, index);\n    }\n\n    public static String getStubAuthority(int index) {\n        return String.format(Locale.ENGLISH, \"%s%d\", STUB_CP_AUTHORITY, index);\n    }\n\n    public static class Wifi {\n        public static boolean FAKE_WIFI_STATE = false;\n        public static String DEFAULT_BSSID = \"66:55:44:33:22:11\";\n        public static String DEFAULT_MAC = \"11:22:33:44:55:66\";\n        public static String DEFAULT_SSID = \"VirtualApp\";\n\n        public static String BSSID = DEFAULT_BSSID;\n        public static String MAC = DEFAULT_MAC;\n        public static String SSID = DEFAULT_SSID;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/ArtDexOptimizer.java",
    "content": "package com.lody.virtual.helper;\n\nimport android.os.Build;\n\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\n\nimport mirror.dalvik.system.VMRuntime;\n\n/**\n * @author Lody\n */\npublic class ArtDexOptimizer {\n\n    /**\n     * Optimize the dex in compile mode.\n     *\n     * @param dexFilePath dex file path\n     * @param oatFilePath oat file path\n     * @throws IOException\n     */\n    public static void compileDex2Oat(String dexFilePath, String oatFilePath) throws IOException {\n        final File oatFile = new File(oatFilePath);\n        if (!oatFile.exists()) {\n            oatFile.getParentFile().mkdirs();\n        }\n\n        final List<String> commandAndParams = new ArrayList<>();\n        commandAndParams.add(\"dex2oat\");\n        // for 7.1.1, duplicate class fix\n        if (Build.VERSION.SDK_INT >= 24) {\n            commandAndParams.add(\"--runtime-arg\");\n            commandAndParams.add(\"-classpath\");\n            commandAndParams.add(\"--runtime-arg\");\n            commandAndParams.add(\"&\");\n        }\n        commandAndParams.add(\"--dex-file=\" + dexFilePath);\n        commandAndParams.add(\"--oat-file=\" + oatFilePath);\n        commandAndParams.add(\"--instruction-set=\" + VMRuntime.getCurrentInstructionSet.call());\n        commandAndParams.add(\"--compiler-filter=everything\");\n        if (Build.VERSION.SDK_INT >= 22 && !BuildCompat.isQ()) {\n            commandAndParams.add(\"--compile-pic\");\n        }\n        if (Build.VERSION.SDK_INT > 25) {\n            // commandAndParams.add(\"--compiler-filter=quicken\");\n            commandAndParams.add(\"--inline-max-code-units=0\");\n        } else {\n            // commandAndParams.add(\"--compiler-filter=interpret-only\");\n            if (Build.VERSION.SDK_INT >= 23) {\n                commandAndParams.add(\"--inline-depth-limit=0\");\n            }\n        }\n\n        final ProcessBuilder pb = new ProcessBuilder(commandAndParams);\n        pb.redirectErrorStream(true);\n        final Process dex2oatProcess = pb.start();\n        StreamConsumer.consumeInputStream(dex2oatProcess.getInputStream());\n        StreamConsumer.consumeInputStream(dex2oatProcess.getErrorStream());\n        try {\n            final int ret = dex2oatProcess.waitFor();\n            if (ret != 0) {\n                throw new IOException(\"dex2oat works unsuccessfully, exit code: \" + ret);\n            }\n        } catch (InterruptedException e) {\n            throw new IOException(\"dex2oat is interrupted, msg: \" + e.getMessage(), e);\n        }\n    }\n\n    private static class StreamConsumer {\n        static final Executor STREAM_CONSUMER = Executors.newSingleThreadExecutor();\n\n        static void consumeInputStream(final InputStream is) {\n            STREAM_CONSUMER.execute(new Runnable() {\n                @Override\n                public void run() {\n                    if (is == null) {\n                        return;\n                    }\n                    final byte[] buffer = new byte[256];\n                    try {\n                        while ((is.read(buffer)) > 0) {\n                            // To satisfy checkstyle rules.\n                        }\n                    } catch (IOException ignored) {\n                        // Ignored.\n                    } finally {\n                        try {\n                            is.close();\n                        } catch (Exception ignored) {\n                            // Ignored.\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/ParcelHelper.java",
    "content": "package com.lody.virtual.helper;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class ParcelHelper {\n\n    public static void writeMeta(Parcel p, Bundle meta) {\n        Map<String, String> map = new HashMap<>();\n        if (meta != null) {\n            for (String key : meta.keySet()) {\n                map.put(key, meta.getString(key));\n            }\n        }\n        p.writeMap(map);\n    }\n\n    public static Bundle readMeta(Parcel p) {\n        Bundle meta = new Bundle();\n        //noinspection unchecked\n        Map<String, String> map = p.readHashMap(String.class.getClassLoader());\n        for (Map.Entry<String, String> entry : map.entrySet()) {\n            meta.putString(entry.getKey(), entry.getValue());\n        }\n        return meta;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/PersistenceLayer.java",
    "content": "package com.lody.virtual.helper;\n\nimport android.os.Parcel;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * @author Lody\n */\npublic abstract class PersistenceLayer {\n\n    private File mPersistenceFile;\n\n    public PersistenceLayer(File persistenceFile) {\n        this.mPersistenceFile = persistenceFile;\n    }\n\n    public final File getPersistenceFile() {\n        return mPersistenceFile;\n    }\n\n    public abstract int getCurrentVersion();\n\n    public void writeMagic(Parcel p) {\n    }\n\n    public boolean verifyMagic(Parcel p) {\n        return true;\n    }\n\n    public abstract void writePersistenceData(Parcel p);\n\n    public abstract void readPersistenceData(Parcel p);\n\n    public boolean onVersionConflict(int fileVersion, int currentVersion) {\n        return false;\n    }\n\n    public void onPersistenceFileDamage() {\n    }\n\n    public void save() {\n        Parcel p = Parcel.obtain();\n        try {\n            writeMagic(p);\n            p.writeInt(getCurrentVersion());\n            writePersistenceData(p);\n            FileOutputStream fos = new FileOutputStream(mPersistenceFile);\n            fos.write(p.marshall());\n            fos.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n    }\n\n    public void read() {\n        File file = mPersistenceFile;\n        Parcel p = Parcel.obtain();\n        try {\n            FileInputStream fis = new FileInputStream(file);\n            byte[] bytes = new byte[(int) file.length()];\n            int len = fis.read(bytes);\n            fis.close();\n            if (len != bytes.length) {\n                throw new IOException(\"Unable to read Persistence file.\");\n            }\n            p.unmarshall(bytes, 0, bytes.length);\n            p.setDataPosition(0);\n            if (!verifyMagic(p)) {\n                onPersistenceFileDamage();\n                throw new IOException(\"Invalid persistence file.\");\n            }\n            int fileVersion = p.readInt();\n            int currentVersion = getCurrentVersion();\n            if (fileVersion != getCurrentVersion()) {\n                if (!onVersionConflict(fileVersion, currentVersion)) {\n                    throw new IOException(\"Unable to process the bad version persistence file.\");\n                }\n            }\n            readPersistenceData(p);\n        } catch (Exception e) {\n            if (!(e instanceof FileNotFoundException)) {\n                e.printStackTrace();\n            }\n        } finally {\n            p.recycle();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/ArrayMap.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * ArrayMap is a generic key->value mapping data structure that is\n * designed to be more memory efficient than a traditional {@link java.util.HashMap},\n * this implementation is a version of the platform's\n * {@link android.util.ArrayMap} that can be used on older versions of the platform.\n * It keeps its mappings in an array data structure -- an integer array of hash\n * codes for each item, and an Object array of the key/value pairs.  This allows it to\n * avoid having to create an extra object for every entry put in to the map, and it\n * also tries to control the growth of the size of these arrays more aggressively\n * (since growing them only requires copying the entries in the array, not rebuilding\n * a hash map).\n *\n * <p>If you don't need the standard Java container APIs provided here (iterators etc),\n * consider using {@link SimpleArrayMap} instead.</p>\n *\n * <p>Note that this implementation is not intended to be appropriate for data structures\n * that may contain large numbers of items.  It is generally slower than a traditional\n * HashMap, since lookups require a binary search and adds and removes require inserting\n * and deleting entries in the array.  For containers holding up to hundreds of items,\n * the performance difference is not significant, less than 50%.</p>\n *\n * <p>Because this container is intended to better balance memory use, unlike most other\n * standard Java containers it will shrink its array as items are removed from it.  Currently\n * you have no control over this shrinking -- if you set a capacity and then remove an\n * item, it may reduce the capacity to better match the current size.  In the future an\n * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>\n */\npublic class ArrayMap<K, V> extends SimpleArrayMap<K, V> implements Map<K, V> {\n    MapCollections<K, V> mCollections;\n\n    public ArrayMap() {\n        super();\n    }\n\n    /**\n     * Create a new ArrayMap with a given initial capacity.\n     */\n    public ArrayMap(int capacity) {\n        super(capacity);\n    }\n\n    /**\n     * Create a new ArrayMap with the mappings from the given ArrayMap.\n     */\n    public ArrayMap(SimpleArrayMap map) {\n        super(map);\n    }\n\n    private MapCollections<K, V> getCollection() {\n        if (mCollections == null) {\n            mCollections = new MapCollections<K, V>() {\n                @Override\n                protected int colGetSize() {\n                    return mSize;\n                }\n\n                @Override\n                protected Object colGetEntry(int index, int offset) {\n                    return mArray[(index<<1) + offset];\n                }\n\n                @Override\n                protected int colIndexOfKey(Object key) {\n                    return indexOfKey(key);\n                }\n\n                @Override\n                protected int colIndexOfValue(Object value) {\n                    return indexOfValue(value);\n                }\n\n                @Override\n                protected Map<K, V> colGetMap() {\n                    return ArrayMap.this;\n                }\n\n                @Override\n                protected void colPut(K key, V value) {\n                    put(key, value);\n                }\n\n                @Override\n                protected V colSetValue(int index, V value) {\n                    return setValueAt(index, value);\n                }\n\n                @Override\n                protected void colRemoveAt(int index) {\n                    removeAt(index);\n                }\n\n                @Override\n                protected void colClear() {\n                    clear();\n                }\n            };\n        }\n        return mCollections;\n    }\n\n    /**\n     * Determine if the array map contains all of the keys in the given collection.\n     * @param collection The collection whose contents are to be checked against.\n     * @return Returns true if this array map contains a key for every entry\n     * in <var>collection</var>, else returns false.\n     */\n    public boolean containsAll(Collection<?> collection) {\n        return MapCollections.containsAllHelper(this, collection);\n    }\n\n    /**\n     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>\n     * @param map The map whose contents are to be retrieved.\n     */\n    @Override\n    public void putAll(Map<? extends K, ? extends V> map) {\n        ensureCapacity(mSize + map.size());\n        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {\n            put(entry.getKey(), entry.getValue());\n        }\n    }\n\n    /**\n     * Remove all keys in the array map that exist in the given collection.\n     * @param collection The collection whose contents are to be used to remove keys.\n     * @return Returns true if any keys were removed from the array map, else false.\n     */\n    public boolean removeAll(Collection<?> collection) {\n        return MapCollections.removeAllHelper(this, collection);\n    }\n\n    /**\n     * Remove all keys in the array map that do <b>not</b> exist in the given collection.\n     * @param collection The collection whose contents are to be used to determine which\n     * keys to keep.\n     * @return Returns true if any keys were removed from the array map, else false.\n     */\n    public boolean retainAll(Collection<?> collection) {\n        return MapCollections.retainAllHelper(this, collection);\n    }\n\n    /**\n     * Return a {@link java.util.Set} for iterating over and interacting with all mappings\n     * in the array map.\n     *\n     * <p><b>Note:</b> this is a very inefficient way to access the array contents, it\n     * requires generating a number of temporary objects.</p>\n     *\n     * <p><b>Note:</b></p> the semantics of this\n     * Set are subtly different than that of a {@link java.util.HashMap}: most important,\n     * the {@link java.util.Map.Entry Map.Entry} object returned by its iterator is a single\n     * object that exists for the entire iterator, so you can <b>not</b> hold on to it\n     * after calling {@link java.util.Iterator#next() Iterator.next}.</p>\n     */\n    @Override\n    public Set<Entry<K, V>> entrySet() {\n        return getCollection().getEntrySet();\n    }\n\n    /**\n     * Return a {@link java.util.Set} for iterating over and interacting with all keys\n     * in the array map.\n     *\n     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it\n     * requires generating a number of temporary objects.</p>\n     */\n    @Override\n    public Set<K> keySet() {\n        return getCollection().getKeySet();\n    }\n\n    /**\n     * Return a {@link java.util.Collection} for iterating over and interacting with all values\n     * in the array map.\n     *\n     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it\n     * requires generating a number of temporary objects.</p>\n     */\n    @Override\n    public Collection<V> values() {\n        return getCollection().getValues();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/ArraySet.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\nimport android.util.Log;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\n\n/**\n * ArraySet is a generic set data structure that is designed to be more memory efficient than a\n * traditional {@link java.util.HashSet}.  The design is very similar to\n * {@link ArrayMap}, with all of the caveats described there.  This implementation is\n * separate from ArrayMap, however, so the Object array contains only one item for each\n * entry in the set (instead of a pair for a mapping).\n *\n * <p>Note that this implementation is not intended to be appropriate for data structures\n * that may contain large numbers of items.  It is generally slower than a traditional\n * HashSet, since lookups require a binary search and adds and removes require inserting\n * and deleting entries in the array.  For containers holding up to hundreds of items,\n * the performance difference is not significant, less than 50%.</p>\n *\n * <p>Because this container is intended to better balance memory use, unlike most other\n * standard Java containers it will shrink its array as items are removed from it.  Currently\n * you have no control over this shrinking -- if you set a capacity and then remove an\n * item, it may reduce the capacity to better match the current size.  In the future an\n * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>\n */\npublic final class ArraySet<E> implements Collection<E>, Set<E> {\n    private static final boolean DEBUG = false;\n    private static final String TAG = \"ArraySet\";\n\n    /**\n     * The minimum amount by which the capacity of a ArraySet will increase.\n     * This is tuned to be relatively space-efficient.\n     */\n    private static final int BASE_SIZE = 4;\n\n    /**\n     * Maximum number of entries to have in array caches.\n     */\n    private static final int CACHE_SIZE = 10;\n\n    /**\n     * Caches of small array objects to avoid spamming garbage.  The cache\n     * Object[] variable is a pointer to a linked list of array objects.\n     * The first entry in the array is a pointer to the next array in the\n     * list; the second entry is a pointer to the int[] hash code array for it.\n     */\n    static Object[] mBaseCache;\n    static int mBaseCacheSize;\n    static Object[] mTwiceBaseCache;\n    static int mTwiceBaseCacheSize;\n\n    int[] mHashes;\n    Object[] mArray;\n    int mSize;\n    MapCollections<E, E> mCollections;\n\n    /**\n     * Create a new empty ArraySet.  The default capacity of an array map is 0, and\n     * will grow once items are added to it.\n     */\n    public ArraySet() {\n        mHashes = ContainerHelpers.EMPTY_INTS;\n        mArray = ContainerHelpers.EMPTY_OBJECTS;\n        mSize = 0;\n    }\n\n    /**\n     * Create a new ArraySet with a given initial capacity.\n     */\n    public ArraySet(int capacity) {\n        if (capacity == 0) {\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n        } else {\n            allocArrays(capacity);\n        }\n        mSize = 0;\n    }\n\n    /**\n     * Create a new ArraySet with the mappings from the given ArraySet.\n     */\n    public ArraySet(ArraySet<E> set) {\n        this();\n        if (set != null) {\n            addAll(set);\n        }\n    }\n\n    /** {@hide} */\n    public ArraySet(Collection<E> set) {\n        this();\n        if (set != null) {\n            addAll(set);\n        }\n    }\n\n    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {\n        if (hashes.length == (BASE_SIZE*2)) {\n            synchronized (ArraySet.class) {\n                if (mTwiceBaseCacheSize < CACHE_SIZE) {\n                    array[0] = mTwiceBaseCache;\n                    array[1] = hashes;\n                    for (int i=size-1; i>=2; i--) {\n                        array[i] = null;\n                    }\n                    mTwiceBaseCache = array;\n                    mTwiceBaseCacheSize++;\n                    if (DEBUG) Log.d(TAG, \"Storing 2x cache \" + array\n                            + \" now have \" + mTwiceBaseCacheSize + \" entries\");\n                }\n            }\n        } else if (hashes.length == BASE_SIZE) {\n            synchronized (ArraySet.class) {\n                if (mBaseCacheSize < CACHE_SIZE) {\n                    array[0] = mBaseCache;\n                    array[1] = hashes;\n                    for (int i=size-1; i>=2; i--) {\n                        array[i] = null;\n                    }\n                    mBaseCache = array;\n                    mBaseCacheSize++;\n                    if (DEBUG) Log.d(TAG, \"Storing 1x cache \" + array\n                            + \" now have \" + mBaseCacheSize + \" entries\");\n                }\n            }\n        }\n    }\n\n    private int indexOf(Object key, int hash) {\n        final int N = mSize;\n\n        // Important fast case: if nothing is in here, nothing to look for.\n        if (N == 0) {\n            return ~0;\n        }\n\n        int index = ContainerHelpers.binarySearch(mHashes, N, hash);\n\n        // If the hash code wasn't found, then we have no entry for this key.\n        if (index < 0) {\n            return index;\n        }\n\n        // If the key at the returned index matches, that's what we want.\n        if (key.equals(mArray[index])) {\n            return index;\n        }\n\n        // Search for a matching key after the index.\n        int end;\n        for (end = index + 1; end < N && mHashes[end] == hash; end++) {\n            if (key.equals(mArray[end])) return end;\n        }\n\n        // Search for a matching key before the index.\n        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {\n            if (key.equals(mArray[i])) return i;\n        }\n\n        // Key not found -- return negative value indicating where a\n        // new entry for this key should go.  We use the end of the\n        // hash chain to reduce the number of array entries that will\n        // need to be copied when inserting.\n        return ~end;\n    }\n\n    private int indexOfNull() {\n        final int N = mSize;\n\n        // Important fast case: if nothing is in here, nothing to look for.\n        if (N == 0) {\n            return ~0;\n        }\n\n        int index = ContainerHelpers.binarySearch(mHashes, N, 0);\n\n        // If the hash code wasn't found, then we have no entry for this key.\n        if (index < 0) {\n            return index;\n        }\n\n        // If the key at the returned index matches, that's what we want.\n        if (null == mArray[index]) {\n            return index;\n        }\n\n        // Search for a matching key after the index.\n        int end;\n        for (end = index + 1; end < N && mHashes[end] == 0; end++) {\n            if (null == mArray[end]) return end;\n        }\n\n        // Search for a matching key before the index.\n        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {\n            if (null == mArray[i]) return i;\n        }\n\n        // Key not found -- return negative value indicating where a\n        // new entry for this key should go.  We use the end of the\n        // hash chain to reduce the number of array entries that will\n        // need to be copied when inserting.\n        return ~end;\n    }\n\n    private void allocArrays(final int size) {\n        if (size == (BASE_SIZE*2)) {\n            synchronized (ArraySet.class) {\n                if (mTwiceBaseCache != null) {\n                    final Object[] array = mTwiceBaseCache;\n                    mArray = array;\n                    mTwiceBaseCache = (Object[])array[0];\n                    mHashes = (int[])array[1];\n                    array[0] = array[1] = null;\n                    mTwiceBaseCacheSize--;\n                    if (DEBUG) Log.d(TAG, \"Retrieving 2x cache \" + mHashes\n                            + \" now have \" + mTwiceBaseCacheSize + \" entries\");\n                    return;\n                }\n            }\n        } else if (size == BASE_SIZE) {\n            synchronized (ArraySet.class) {\n                if (mBaseCache != null) {\n                    final Object[] array = mBaseCache;\n                    mArray = array;\n                    mBaseCache = (Object[])array[0];\n                    mHashes = (int[])array[1];\n                    array[0] = array[1] = null;\n                    mBaseCacheSize--;\n                    if (DEBUG) Log.d(TAG, \"Retrieving 1x cache \" + mHashes\n                            + \" now have \" + mBaseCacheSize + \" entries\");\n                    return;\n                }\n            }\n        }\n\n        mHashes = new int[size];\n        mArray = new Object[size];\n    }\n\n    /**\n     * Make the array map empty.  All storage is released.\n     */\n    @Override\n    public void clear() {\n        if (mSize != 0) {\n            freeArrays(mHashes, mArray, mSize);\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n            mSize = 0;\n        }\n    }\n\n    /**\n     * Ensure the array map can hold at least <var>minimumCapacity</var>\n     * items.\n     */\n    public void ensureCapacity(int minimumCapacity) {\n        if (mHashes.length < minimumCapacity) {\n            final int[] ohashes = mHashes;\n            final Object[] oarray = mArray;\n            allocArrays(minimumCapacity);\n            if (mSize > 0) {\n                System.arraycopy(ohashes, 0, mHashes, 0, mSize);\n                System.arraycopy(oarray, 0, mArray, 0, mSize);\n            }\n            freeArrays(ohashes, oarray, mSize);\n        }\n    }\n\n    /**\n     * Check whether a value exists in the set.\n     *\n     * @param key The value to search for.\n     * @return Returns true if the value exists, else false.\n     */\n    @Override\n    public boolean contains(Object key) {\n        return indexOf(key) >= 0;\n    }\n\n    /**\n     * Returns the index of a value in the set.\n     *\n     * @param key The value to search for.\n     * @return Returns the index of the value if it exists, else a negative integer.\n     */\n    public int indexOf(Object key) {\n        return key == null ? indexOfNull() : indexOf(key, key.hashCode());\n    }\n\n    /**\n     * Return the value at the given index in the array.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @return Returns the value stored at the given index.\n     */\n    public E valueAt(int index) {\n        return (E)mArray[index];\n    }\n\n    /**\n     * Return true if the array map contains no items.\n     */\n    @Override\n    public boolean isEmpty() {\n        return mSize <= 0;\n    }\n\n    /**\n     * Adds the specified object to this set. The set is not modified if it\n     * already contains the object.\n     *\n     * @param value the object to add.\n     * @return {@code true} if this set is modified, {@code false} otherwise.\n     * @throws ClassCastException\n     *             when the class of the object is inappropriate for this set.\n     */\n    @Override\n    public boolean add(E value) {\n        final int hash;\n        int index;\n        if (value == null) {\n            hash = 0;\n            index = indexOfNull();\n        } else {\n            hash = value.hashCode();\n            index = indexOf(value, hash);\n        }\n        if (index >= 0) {\n            return false;\n        }\n\n        index = ~index;\n        if (mSize >= mHashes.length) {\n            final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))\n                    : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);\n\n            if (DEBUG) Log.d(TAG, \"add: grow from \" + mHashes.length + \" to \" + n);\n\n            final int[] ohashes = mHashes;\n            final Object[] oarray = mArray;\n            allocArrays(n);\n\n            if (mHashes.length > 0) {\n                if (DEBUG) Log.d(TAG, \"add: copy 0-\" + mSize + \" to 0\");\n                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);\n                System.arraycopy(oarray, 0, mArray, 0, oarray.length);\n            }\n\n            freeArrays(ohashes, oarray, mSize);\n        }\n\n        if (index < mSize) {\n            if (DEBUG) Log.d(TAG, \"add: move \" + index + \"-\" + (mSize-index)\n                    + \" to \" + (index+1));\n            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);\n            System.arraycopy(mArray, index, mArray, index + 1, mSize - index);\n        }\n\n        mHashes[index] = hash;\n        mArray[index] = value;\n        mSize++;\n        return true;\n    }\n\n    /**\n     * Perform a {@link #add(Object)} of all values in <var>array</var>\n     * @param array The array whose contents are to be retrieved.\n     */\n    public void addAll(ArraySet<? extends E> array) {\n        final int N = array.mSize;\n        ensureCapacity(mSize + N);\n        if (mSize == 0) {\n            if (N > 0) {\n                System.arraycopy(array.mHashes, 0, mHashes, 0, N);\n                System.arraycopy(array.mArray, 0, mArray, 0, N);\n                mSize = N;\n            }\n        } else {\n            for (int i=0; i<N; i++) {\n                add(array.valueAt(i));\n            }\n        }\n    }\n\n    /**\n     * Removes the specified object from this set.\n     *\n     * @param object the object to remove.\n     * @return {@code true} if this set was modified, {@code false} otherwise.\n     */\n    @Override\n    public boolean remove(Object object) {\n        final int index = indexOf(object);\n        if (index >= 0) {\n            removeAt(index);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Remove the key/value mapping at the given index.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @return Returns the value that was stored at this index.\n     */\n    public E removeAt(int index) {\n        final Object old = mArray[index];\n        if (mSize <= 1) {\n            // Now empty.\n            if (DEBUG) Log.d(TAG, \"remove: shrink from \" + mHashes.length + \" to 0\");\n            freeArrays(mHashes, mArray, mSize);\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n            mSize = 0;\n        } else {\n            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {\n                // Shrunk enough to reduce size of arrays.  We don't allow it to\n                // shrink smaller than (BASE_SIZE*2) to avoid flapping between\n                // that and BASE_SIZE.\n                final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2);\n\n                if (DEBUG) Log.d(TAG, \"remove: shrink from \" + mHashes.length + \" to \" + n);\n\n                final int[] ohashes = mHashes;\n                final Object[] oarray = mArray;\n                allocArrays(n);\n\n                mSize--;\n                if (index > 0) {\n                    if (DEBUG) Log.d(TAG, \"remove: copy from 0-\" + index + \" to 0\");\n                    System.arraycopy(ohashes, 0, mHashes, 0, index);\n                    System.arraycopy(oarray, 0, mArray, 0, index);\n                }\n                if (index < mSize) {\n                    if (DEBUG) Log.d(TAG, \"remove: copy from \" + (index+1) + \"-\" + mSize\n                            + \" to \" + index);\n                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);\n                    System.arraycopy(oarray, index + 1, mArray, index, mSize - index);\n                }\n            } else {\n                mSize--;\n                if (index < mSize) {\n                    if (DEBUG) Log.d(TAG, \"remove: move \" + (index+1) + \"-\" + mSize\n                            + \" to \" + index);\n                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);\n                    System.arraycopy(mArray, index + 1, mArray, index, mSize - index);\n                }\n                mArray[mSize] = null;\n            }\n        }\n        return (E)old;\n    }\n\n    /**\n     * Perform a {@link #remove(Object)} of all values in <var>array</var>\n     * @param array The array whose contents are to be removed.\n     */\n    public boolean removeAll(ArraySet<? extends E> array) {\n        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first\n        //       pass, use the property that the sets are sorted by hash to make this linear passes\n        //       (except for hash collisions, which means worst case still n*m), then do one\n        //       collection pass into a new array. This avoids binary searches and excessive memcpy.\n        final int N = array.mSize;\n\n        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all\n        //       the single results, compare size before and after.\n        final int originalSize = mSize;\n        for (int i = 0; i < N; i++) {\n            remove(array.valueAt(i));\n        }\n        return originalSize != mSize;\n    }\n\n    /**\n     * Return the number of items in this array map.\n     */\n    @Override\n    public int size() {\n        return mSize;\n    }\n\n    @Override\n    public Object[] toArray() {\n        Object[] result = new Object[mSize];\n        System.arraycopy(mArray, 0, result, 0, mSize);\n        return result;\n    }\n\n    @Override\n    public <T> T[] toArray(T[] array) {\n        if (array.length < mSize) {\n            @SuppressWarnings(\"unchecked\") T[] newArray\n                = (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);\n            array = newArray;\n        }\n        System.arraycopy(mArray, 0, array, 0, mSize);\n        if (array.length > mSize) {\n            array[mSize] = null;\n        }\n        return array;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * <p>This implementation returns false if the object is not a set, or\n     * if the sets have different sizes.  Otherwise, for each value in this\n     * set, it checks to make sure the value also exists in the other set.\n     * If any value doesn't exist, the method returns false; otherwise, it\n     * returns true.\n     */\n    @Override\n    public boolean equals(Object object) {\n        if (this == object) {\n            return true;\n        }\n        if (object instanceof Set) {\n            Set<?> set = (Set<?>) object;\n            if (size() != set.size()) {\n                return false;\n            }\n\n            try {\n                for (int i=0; i<mSize; i++) {\n                    E mine = valueAt(i);\n                    if (!set.contains(mine)) {\n                        return false;\n                    }\n                }\n            } catch (NullPointerException ignored) {\n                return false;\n            } catch (ClassCastException ignored) {\n                return false;\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int hashCode() {\n        final int[] hashes = mHashes;\n        int result = 0;\n        for (int i = 0, s = mSize; i < s; i++) {\n            result += hashes[i];\n        }\n        return result;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * <p>This implementation composes a string by iterating over its values. If\n     * this set contains itself as a value, the string \"(this Set)\"\n     * will appear in its place.\n     */\n    @Override\n    public String toString() {\n        if (isEmpty()) {\n            return \"{}\";\n        }\n\n        StringBuilder buffer = new StringBuilder(mSize * 14);\n        buffer.append('{');\n        for (int i=0; i<mSize; i++) {\n            if (i > 0) {\n                buffer.append(\", \");\n            }\n            Object value = valueAt(i);\n            if (value != this) {\n                buffer.append(value);\n            } else {\n                buffer.append(\"(this Set)\");\n            }\n        }\n        buffer.append('}');\n        return buffer.toString();\n    }\n\n    // ------------------------------------------------------------------------\n    // Interop with traditional Java containers.  Not as efficient as using\n    // specialized collection APIs.\n    // ------------------------------------------------------------------------\n\n    private MapCollections<E, E> getCollection() {\n        if (mCollections == null) {\n            mCollections = new MapCollections<E, E>() {\n                @Override\n                protected int colGetSize() {\n                    return mSize;\n                }\n\n                @Override\n                protected Object colGetEntry(int index, int offset) {\n                    return mArray[index];\n                }\n\n                @Override\n                protected int colIndexOfKey(Object key) {\n                    return indexOf(key);\n                }\n\n                @Override\n                protected int colIndexOfValue(Object value) {\n                    return indexOf(value);\n                }\n\n                @Override\n                protected Map<E, E> colGetMap() {\n                    throw new UnsupportedOperationException(\"not a map\");\n                }\n\n                @Override\n                protected void colPut(E key, E value) {\n                    add(key);\n                }\n\n                @Override\n                protected E colSetValue(int index, E value) {\n                    throw new UnsupportedOperationException(\"not a map\");\n                }\n\n                @Override\n                protected void colRemoveAt(int index) {\n                    removeAt(index);\n                }\n\n                @Override\n                protected void colClear() {\n                    clear();\n                }\n            };\n        }\n        return mCollections;\n    }\n\n    /**\n     * Return an {@link java.util.Iterator} over all values in the set.\n     *\n     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it\n     * requires generating a number of temporary objects and allocates additional state\n     * information associated with the container that will remain for the life of the container.</p>\n     */\n    @Override\n    public Iterator<E> iterator() {\n        return getCollection().getKeySet().iterator();\n    }\n\n    /**\n     * Determine if the array set contains all of the values in the given collection.\n     * @param collection The collection whose contents are to be checked against.\n     * @return Returns true if this array set contains a value for every entry\n     * in <var>collection</var>, else returns false.\n     */\n    @Override\n    public boolean containsAll(Collection<?> collection) {\n        Iterator<?> it = collection.iterator();\n        while (it.hasNext()) {\n            if (!contains(it.next())) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Perform an {@link #add(Object)} of all values in <var>collection</var>\n     * @param collection The collection whose contents are to be retrieved.\n     */\n    @Override\n    public boolean addAll(Collection<? extends E> collection) {\n        ensureCapacity(mSize + collection.size());\n        boolean added = false;\n        for (E value : collection) {\n            added |= add(value);\n        }\n        return added;\n    }\n\n    /**\n     * Remove all values in the array set that exist in the given collection.\n     * @param collection The collection whose contents are to be used to remove values.\n     * @return Returns true if any values were removed from the array set, else false.\n     */\n    @Override\n    public boolean removeAll(Collection<?> collection) {\n        boolean removed = false;\n        for (Object value : collection) {\n            removed |= remove(value);\n        }\n        return removed;\n    }\n\n    /**\n     * Remove all values in the array set that do <b>not</b> exist in the given collection.\n     * @param collection The collection whose contents are to be used to determine which\n     * values to keep.\n     * @return Returns true if any values were removed from the array set, else false.\n     */\n    @Override\n    public boolean retainAll(Collection<?> collection) {\n        boolean removed = false;\n        for (int i=mSize-1; i>=0; i--) {\n            if (!collection.contains(mArray[i])) {\n                removeAt(i);\n                removed = true;\n            }\n        }\n        return removed;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/ContainerHelpers.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\nclass ContainerHelpers {\n    static final int[] EMPTY_INTS = new int[0];\n    static final long[] EMPTY_LONGS = new long[0];\n    static final Object[] EMPTY_OBJECTS = new Object[0];\n\n    public static int idealIntArraySize(int need) {\n        return idealByteArraySize(need * 4) / 4;\n    }\n\n    public static int idealLongArraySize(int need) {\n        return idealByteArraySize(need * 8) / 8;\n    }\n\n    public static int idealByteArraySize(int need) {\n        for (int i = 4; i < 32; i++)\n            if (need <= (1 << i) - 12)\n                return (1 << i) - 12;\n\n        return need;\n    }\n\n    public static boolean equal(Object a, Object b) {\n        return a == b || (a != null && a.equals(b));\n    }\n\n    // This is Arrays.binarySearch(), but doesn't do any argument validation.\n    static int binarySearch(int[] array, int size, int value) {\n        int lo = 0;\n        int hi = size - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            int midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    static int binarySearch(long[] array, int size, long value) {\n        int lo = 0;\n        int hi = size - 1;\n\n        while (lo <= hi) {\n            final int mid = (lo + hi) >>> 1;\n            final long midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/IntArray.java",
    "content": "/*\n *  Copyright 2011 Alexey Andreev.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *       http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.lody.virtual.helper.collection;\n\nimport java.util.Arrays;\n\n/**\n * @author Lody\n */\npublic class IntArray {\n    private static final int[] EMPTY_ARRAY = new int[0];\n    private int[] mData;\n    private int mSize;\n\n    private IntArray() {\n    }\n\n    public IntArray(int capacity) {\n        this.mData = new int[capacity];\n    }\n\n    public static IntArray of(int... values) {\n        IntArray array = new IntArray();\n        array.mData = Arrays.copyOf(values, values.length);\n        array.mSize = values.length;\n        return array;\n    }\n\n    public void clear() {\n        mSize = 0;\n    }\n\n    public void optimize() {\n        if (mSize > mData.length) {\n            mData = Arrays.copyOf(mData, mSize);\n        }\n    }\n\n    public int[] getAll() {\n        return mSize > 0 ? Arrays.copyOf(mData, mSize) : EMPTY_ARRAY;\n    }\n\n    public int get(int index) {\n        return mData[index];\n    }\n\n    public int[] getRange(int start, int end) {\n        return Arrays.copyOfRange(mData, start, end);\n    }\n\n    public void set(int index, int value) {\n        if (index >= mSize) {\n            throw new IndexOutOfBoundsException(\"Index \" + index + \" is greater than the list size \" + mSize);\n        }\n        mData[index] = value;\n    }\n\n    private void ensureCapacity() {\n        if (mSize <= mData.length) {\n            return;\n        }\n        int newCap = mData.length;\n        while (mSize > newCap) {\n            newCap = newCap * 3 / 2 + 1;\n        }\n        mData = Arrays.copyOf(mData, newCap);\n    }\n\n    public int size() {\n        return mSize;\n    }\n\n    public void addAll(int[] items) {\n        int target = mSize;\n        mSize += items.length;\n        ensureCapacity();\n        System.arraycopy(items, 0, mData, target, items.length);\n    }\n\n    public void add(int item) {\n        ++mSize;\n        ensureCapacity();\n        mData[mSize - 1] = item;\n    }\n\n    public void remove(int index) {\n        remove(index, 1);\n    }\n\n    public void remove(int index, int count) {\n        System.arraycopy(mData, index + count, mData, index, mSize - index - count);\n        mSize -= count;\n    }\n\n    public boolean contains(int item) {\n        for (int i = 0; i < mSize; ++i) {\n            if (mData[i] == item) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/MapCollections.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Helper for writing standard Java collection interfaces to a data\n * structure like {@link ArrayMap}.\n * @hide\n */\nabstract class MapCollections<K, V> {\n    EntrySet mEntrySet;\n    KeySet mKeySet;\n    ValuesCollection mValues;\n\n    public static <K, V> boolean containsAllHelper(Map<K, V> map, Collection<?> collection) {\n        Iterator<?> it = collection.iterator();\n        while (it.hasNext()) {\n            if (!map.containsKey(it.next())) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static <K, V> boolean removeAllHelper(Map<K, V> map, Collection<?> collection) {\n        int oldSize = map.size();\n        Iterator<?> it = collection.iterator();\n        while (it.hasNext()) {\n            map.remove(it.next());\n        }\n        return oldSize != map.size();\n    }\n\n        public static <K, V> boolean retainAllHelper(Map<K, V> map, Collection<?> collection) {\n        int oldSize = map.size();\n        Iterator<K> it = map.keySet().iterator();\n        while (it.hasNext()) {\n            if (!collection.contains(it.next())) {\n                it.remove();\n            }\n        }\n        return oldSize != map.size();\n    };\n\n        public static <T> boolean equalsSetHelper(Set<T> set, Object object) {\n        if (set == object) {\n            return true;\n        }\n        if (object instanceof Set) {\n            Set<?> s = (Set<?>) object;\n\n            try {\n                return set.size() == s.size() && set.containsAll(s);\n            } catch (NullPointerException ignored) {\n                return false;\n            } catch (ClassCastException ignored) {\n                return false;\n            }\n        }\n        return false;\n    };\n\n        public Object[] toArrayHelper(int offset) {\n        final int N = colGetSize();\n        Object[] result = new Object[N];\n        for (int i=0; i<N; i++) {\n            result[i] = colGetEntry(i, offset);\n        }\n        return result;\n    };\n\n    public <T> T[] toArrayHelper(T[] array, int offset) {\n        final int N  = colGetSize();\n        if (array.length < N) {\n            @SuppressWarnings(\"unchecked\") T[] newArray\n                = (T[]) Array.newInstance(array.getClass().getComponentType(), N);\n            array = newArray;\n        }\n        for (int i=0; i<N; i++) {\n            array[i] = (T)colGetEntry(i, offset);\n        }\n        if (array.length > N) {\n            array[N] = null;\n        }\n        return array;\n    }\n\n    public Set<Map.Entry<K, V>> getEntrySet() {\n        if (mEntrySet == null) {\n            mEntrySet = new EntrySet();\n        }\n        return mEntrySet;\n    }\n\n    public Set<K> getKeySet() {\n        if (mKeySet == null) {\n            mKeySet = new KeySet();\n        }\n        return mKeySet;\n    }\n\n    public Collection<V> getValues() {\n        if (mValues == null) {\n            mValues = new ValuesCollection();\n        }\n        return mValues;\n    }\n\n    protected abstract int colGetSize();\n\n    protected abstract Object colGetEntry(int index, int offset);\n\n    protected abstract int colIndexOfKey(Object key);\n\n    protected abstract int colIndexOfValue(Object key);\n\n    protected abstract Map<K, V> colGetMap();\n\n    protected abstract void colPut(K key, V value);\n\n    protected abstract V colSetValue(int index, V value);\n\n    protected abstract void colRemoveAt(int index);\n\n    protected abstract void colClear();\n\n    final class ArrayIterator<T> implements Iterator<T> {\n        final int mOffset;\n        int mSize;\n        int mIndex;\n        boolean mCanRemove = false;\n\n        ArrayIterator(int offset) {\n            mOffset = offset;\n            mSize = colGetSize();\n        }\n\n        @Override\n        public boolean hasNext() {\n            return mIndex < mSize;\n        }\n\n        @Override\n        public T next() {\n            Object res = colGetEntry(mIndex, mOffset);\n            mIndex++;\n            mCanRemove = true;\n            return (T)res;\n        }\n\n        @Override\n        public void remove() {\n            if (!mCanRemove) {\n                throw new IllegalStateException();\n            }\n            mIndex--;\n            mSize--;\n            mCanRemove = false;\n            colRemoveAt(mIndex);\n        }\n    }\n\n    final class MapIterator implements Iterator<Map.Entry<K, V>>, Map.Entry<K, V> {\n        int mEnd;\n        int mIndex;\n        boolean mEntryValid = false;\n\n        MapIterator() {\n            mEnd = colGetSize() - 1;\n            mIndex = -1;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return mIndex < mEnd;\n        }\n\n        @Override\n        public Map.Entry<K, V> next() {\n            mIndex++;\n            mEntryValid = true;\n            return this;\n        }\n\n        @Override\n        public void remove() {\n            if (!mEntryValid) {\n                throw new IllegalStateException();\n            }\n            colRemoveAt(mIndex);\n            mIndex--;\n            mEnd--;\n            mEntryValid = false;\n        }\n\n        @Override\n        public K getKey() {\n            if (!mEntryValid) {\n                throw new IllegalStateException(\n                        \"This container does not support retaining Map.Entry objects\");\n            }\n            return (K)colGetEntry(mIndex, 0);\n        }\n\n        @Override\n        public V getValue() {\n            if (!mEntryValid) {\n                throw new IllegalStateException(\n                        \"This container does not support retaining Map.Entry objects\");\n            }\n            return (V)colGetEntry(mIndex, 1);\n        }\n\n        @Override\n        public V setValue(V object) {\n            if (!mEntryValid) {\n                throw new IllegalStateException(\n                        \"This container does not support retaining Map.Entry objects\");\n            }\n            return colSetValue(mIndex, object);\n        }\n\n        @Override\n        public final boolean equals(Object o) {\n            if (!mEntryValid) {\n                throw new IllegalStateException(\n                        \"This container does not support retaining Map.Entry objects\");\n            }\n            if (!(o instanceof Map.Entry)) {\n                return false;\n            }\n            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;\n            return ContainerHelpers.equal(e.getKey(), colGetEntry(mIndex, 0))\n                    && ContainerHelpers.equal(e.getValue(), colGetEntry(mIndex, 1));\n        }\n\n        @Override\n        public final int hashCode() {\n            if (!mEntryValid) {\n                throw new IllegalStateException(\n                        \"This container does not support retaining Map.Entry objects\");\n            }\n            final Object key = colGetEntry(mIndex, 0);\n            final Object value = colGetEntry(mIndex, 1);\n            return (key == null ? 0 : key.hashCode()) ^\n                    (value == null ? 0 : value.hashCode());\n        }\n\n        @Override\n        public final String toString() {\n            return getKey() + \"=\" + getValue();\n        }\n    }\n\nfinal class EntrySet implements Set<Map.Entry<K, V>> {\n        @Override\n        public boolean add(Map.Entry<K, V> object) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean addAll(Collection<? extends Map.Entry<K, V>> collection) {\n            int oldSize = colGetSize();\n            for (Map.Entry<K, V> entry : collection) {\n                colPut(entry.getKey(), entry.getValue());\n            }\n            return oldSize != colGetSize();\n        }\n\n        @Override\n        public void clear() {\n            colClear();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            if (!(o instanceof Map.Entry))\n                return false;\n            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;\n            int index = colIndexOfKey(e.getKey());\n            if (index < 0) {\n                return false;\n            }\n            Object foundVal = colGetEntry(index, 1);\n            return ContainerHelpers.equal(foundVal, e.getValue());\n        }\n\n        @Override\n        public boolean containsAll(Collection<?> collection) {\n            Iterator<?> it = collection.iterator();\n            while (it.hasNext()) {\n                if (!contains(it.next())) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return colGetSize() == 0;\n        }\n\n        @Override\n        public Iterator<Map.Entry<K, V>> iterator() {\n            return new MapIterator();\n        }\n\n        @Override\n        public boolean remove(Object object) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean removeAll(Collection<?> collection) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean retainAll(Collection<?> collection) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public int size() {\n            return colGetSize();\n        }\n\n        @Override\n        public Object[] toArray() {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public <T> T[] toArray(T[] array) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean equals(Object object) {\n            return equalsSetHelper(this, object);\n        }\n\n        @Override\n        public int hashCode() {\n            int result = 0;\n            for (int i=colGetSize()-1; i>=0; i--) {\n                final Object key = colGetEntry(i, 0);\n                final Object value = colGetEntry(i, 1);\n                result += ( (key == null ? 0 : key.hashCode()) ^\n                        (value == null ? 0 : value.hashCode()) );\n            }\n            return result;\n        }\n    }\n\nfinal class KeySet implements Set<K> {\n\n        @Override\n        public boolean add(K object) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean addAll(Collection<? extends K> collection) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public void clear() {\n            colClear();\n        }\n\n        @Override\n        public boolean contains(Object object) {\n            return colIndexOfKey(object) >= 0;\n        }\n\n        @Override\n        public boolean containsAll(Collection<?> collection) {\n            return containsAllHelper(colGetMap(), collection);\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return colGetSize() == 0;\n        }\n\n        @Override\n        public Iterator<K> iterator() {\n            return new ArrayIterator<K>(0);\n        }\n\n        @Override\n        public boolean remove(Object object) {\n            int index = colIndexOfKey(object);\n            if (index >= 0) {\n                colRemoveAt(index);\n                return true;\n            }\n            return false;\n        }\n\n        @Override\n        public boolean removeAll(Collection<?> collection) {\n            return removeAllHelper(colGetMap(), collection);\n        }\n\n        @Override\n        public boolean retainAll(Collection<?> collection) {\n            return retainAllHelper(colGetMap(), collection);\n        }\n\n        @Override\n        public int size() {\n            return colGetSize();\n        }\n\n        @Override\n        public Object[] toArray() {\n            return toArrayHelper(0);\n        }\n\n        @Override\n        public <T> T[] toArray(T[] array) {\n            return toArrayHelper(array, 0);\n        }\n\n        @Override\n        public boolean equals(Object object) {\n            return equalsSetHelper(this, object);\n        }\n\n        @Override\n        public int hashCode() {\n            int result = 0;\n            for (int i=colGetSize()-1; i>=0; i--) {\n                Object obj = colGetEntry(i, 0);\n                result += obj == null ? 0 : obj.hashCode();\n            }\n            return result;\n        }\n    }\n\nfinal class ValuesCollection implements Collection<V> {\n\n        @Override\n        public boolean add(V object) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public boolean addAll(Collection<? extends V> collection) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public void clear() {\n            colClear();\n        }\n\n        @Override\n        public boolean contains(Object object) {\n            return colIndexOfValue(object) >= 0;\n        }\n\n        @Override\n        public boolean containsAll(Collection<?> collection) {\n            Iterator<?> it = collection.iterator();\n            while (it.hasNext()) {\n                if (!contains(it.next())) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return colGetSize() == 0;\n        }\n\n        @Override\n        public Iterator<V> iterator() {\n            return new ArrayIterator<V>(1);\n        }\n\n        @Override\n        public boolean remove(Object object) {\n            int index = colIndexOfValue(object);\n            if (index >= 0) {\n                colRemoveAt(index);\n                return true;\n            }\n            return false;\n        }\n\n        @Override\n        public boolean removeAll(Collection<?> collection) {\n            int N = colGetSize();\n            boolean changed = false;\n            for (int i=0; i<N; i++) {\n                Object cur = colGetEntry(i, 1);\n                if (collection.contains(cur)) {\n                    colRemoveAt(i);\n                    i--;\n                    N--;\n                    changed = true;\n                }\n            }\n            return changed;\n        }\n\n        @Override\n        public boolean retainAll(Collection<?> collection) {\n            int N = colGetSize();\n            boolean changed = false;\n            for (int i=0; i<N; i++) {\n                Object cur = colGetEntry(i, 1);\n                if (!collection.contains(cur)) {\n                    colRemoveAt(i);\n                    i--;\n                    N--;\n                    changed = true;\n                }\n            }\n            return changed;\n        }\n\n        @Override\n        public int size() {\n            return colGetSize();\n        }\n\n        @Override\n        public Object[] toArray() {\n            return toArrayHelper(1);\n        }\n\n        @Override\n        public <T> T[] toArray(T[] array) {\n            return toArrayHelper(array, 1);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/SimpleArrayMap.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\nimport android.util.Log;\n\nimport java.util.Map;\n\n/**\n * Base implementation of {@link ArrayMap} that doesn't include any standard Java\n * container API interoperability.  These features are generally heavier-weight ways\n * to interact with the container, so discouraged, but they can be useful to make it\n * easier to use as a drop-in replacement for HashMap.  If you don't need them, this\n * class can be preferrable since it doesn't bring in any of the implementation of those\n * APIs, allowing that code to be stripped by ProGuard.\n */\npublic class SimpleArrayMap<K, V> {\n    private static final boolean DEBUG = false;\n    private static final String TAG = \"ArrayMap\";\n\n    /**\n     * The minimum amount by which the capacity of a ArrayMap will increase.\n     * This is tuned to be relatively space-efficient.\n     */\n    private static final int BASE_SIZE = 4;\n\n    /**\n     * Maximum number of entries to have in array caches.\n     */\n    private static final int CACHE_SIZE = 10;\n\n    /**\n     * Caches of small array objects to avoid spamming garbage.  The cache\n     * Object[] variable is a pointer to a linked list of array objects.\n     * The first entry in the array is a pointer to the next array in the\n     * list; the second entry is a pointer to the int[] hash code array for it.\n     */\n    static Object[] mBaseCache;\n    static int mBaseCacheSize;\n    static Object[] mTwiceBaseCache;\n    static int mTwiceBaseCacheSize;\n\n    int[] mHashes;\n    Object[] mArray;\n    int mSize;\n\n    /**\n     * Create a new empty ArrayMap.  The default capacity of an array map is 0, and\n     * will grow once items are added to it.\n     */\n    public SimpleArrayMap() {\n        mHashes = ContainerHelpers.EMPTY_INTS;\n        mArray = ContainerHelpers.EMPTY_OBJECTS;\n        mSize = 0;\n    }\n\n    /**\n     * Create a new ArrayMap with a given initial capacity.\n     */\n    public SimpleArrayMap(int capacity) {\n        if (capacity == 0) {\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n        } else {\n            allocArrays(capacity);\n        }\n        mSize = 0;\n    }\n\n    /**\n     * Create a new ArrayMap with the mappings from the given ArrayMap.\n     */\n    public SimpleArrayMap(SimpleArrayMap map) {\n        this();\n        if (map != null) {\n            putAll(map);\n        }\n    }\n\n    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {\n        if (hashes.length == (BASE_SIZE*2)) {\n            synchronized (ArrayMap.class) {\n                if (mTwiceBaseCacheSize < CACHE_SIZE) {\n                    array[0] = mTwiceBaseCache;\n                    array[1] = hashes;\n                    for (int i=(size<<1)-1; i>=2; i--) {\n                        array[i] = null;\n                    }\n                    mTwiceBaseCache = array;\n                    mTwiceBaseCacheSize++;\n                    if (DEBUG) Log.d(TAG, \"Storing 2x cache \" + array\n                            + \" now have \" + mTwiceBaseCacheSize + \" entries\");\n                }\n            }\n        } else if (hashes.length == BASE_SIZE) {\n            synchronized (ArrayMap.class) {\n                if (mBaseCacheSize < CACHE_SIZE) {\n                    array[0] = mBaseCache;\n                    array[1] = hashes;\n                    for (int i=(size<<1)-1; i>=2; i--) {\n                        array[i] = null;\n                    }\n                    mBaseCache = array;\n                    mBaseCacheSize++;\n                    if (DEBUG) Log.d(TAG, \"Storing 1x cache \" + array\n                            + \" now have \" + mBaseCacheSize + \" entries\");\n                }\n            }\n        }\n    }\n\n    int indexOf(Object key, int hash) {\n        final int N = mSize;\n\n        // Important fast case: if nothing is in here, nothing to look for.\n        if (N == 0) {\n            return ~0;\n        }\n\n        int index = ContainerHelpers.binarySearch(mHashes, N, hash);\n\n        // If the hash code wasn't found, then we have no entry for this key.\n        if (index < 0) {\n            return index;\n        }\n\n        // If the key at the returned index matches, that's what we want.\n        if (key.equals(mArray[index<<1])) {\n            return index;\n        }\n\n        // Search for a matching key after the index.\n        int end;\n        for (end = index + 1; end < N && mHashes[end] == hash; end++) {\n            if (key.equals(mArray[end << 1])) return end;\n        }\n\n        // Search for a matching key before the index.\n        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {\n            if (key.equals(mArray[i << 1])) return i;\n        }\n\n        // Key not found -- return negative value indicating where a\n        // new entry for this key should go.  We use the end of the\n        // hash chain to reduce the number of array entries that will\n        // need to be copied when inserting.\n        return ~end;\n    }\n\n    int indexOfNull() {\n        final int N = mSize;\n\n        // Important fast case: if nothing is in here, nothing to look for.\n        if (N == 0) {\n            return ~0;\n        }\n\n        int index = ContainerHelpers.binarySearch(mHashes, N, 0);\n\n        // If the hash code wasn't found, then we have no entry for this key.\n        if (index < 0) {\n            return index;\n        }\n\n        // If the key at the returned index matches, that's what we want.\n        if (null == mArray[index<<1]) {\n            return index;\n        }\n\n        // Search for a matching key after the index.\n        int end;\n        for (end = index + 1; end < N && mHashes[end] == 0; end++) {\n            if (null == mArray[end << 1]) return end;\n        }\n\n        // Search for a matching key before the index.\n        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {\n            if (null == mArray[i << 1]) return i;\n        }\n\n        // Key not found -- return negative value indicating where a\n        // new entry for this key should go.  We use the end of the\n        // hash chain to reduce the number of array entries that will\n        // need to be copied when inserting.\n        return ~end;\n    }\n\n    private void allocArrays(final int size) {\n        if (size == (BASE_SIZE*2)) {\n            synchronized (ArrayMap.class) {\n                if (mTwiceBaseCache != null) {\n                    final Object[] array = mTwiceBaseCache;\n                    mArray = array;\n                    mTwiceBaseCache = (Object[])array[0];\n                    mHashes = (int[])array[1];\n                    array[0] = array[1] = null;\n                    mTwiceBaseCacheSize--;\n                    if (DEBUG) Log.d(TAG, \"Retrieving 2x cache \" + mHashes\n                            + \" now have \" + mTwiceBaseCacheSize + \" entries\");\n                    return;\n                }\n            }\n        } else if (size == BASE_SIZE) {\n            synchronized (ArrayMap.class) {\n                if (mBaseCache != null) {\n                    final Object[] array = mBaseCache;\n                    mArray = array;\n                    mBaseCache = (Object[])array[0];\n                    mHashes = (int[])array[1];\n                    array[0] = array[1] = null;\n                    mBaseCacheSize--;\n                    if (DEBUG) Log.d(TAG, \"Retrieving 1x cache \" + mHashes\n                            + \" now have \" + mBaseCacheSize + \" entries\");\n                    return;\n                }\n            }\n        }\n\n        mHashes = new int[size];\n        mArray = new Object[size<<1];\n    }\n\n    /**\n     * Make the array map empty.  All storage is released.\n     */\n    public void clear() {\n        if (mSize != 0) {\n            freeArrays(mHashes, mArray, mSize);\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n            mSize = 0;\n        }\n    }\n\n    /**\n     * Ensure the array map can hold at least <var>minimumCapacity</var>\n     * items.\n     */\n    public void ensureCapacity(int minimumCapacity) {\n        if (mHashes.length < minimumCapacity) {\n            final int[] ohashes = mHashes;\n            final Object[] oarray = mArray;\n            allocArrays(minimumCapacity);\n            if (mSize > 0) {\n                System.arraycopy(ohashes, 0, mHashes, 0, mSize);\n                System.arraycopy(oarray, 0, mArray, 0, mSize<<1);\n            }\n            freeArrays(ohashes, oarray, mSize);\n        }\n    }\n\n    /**\n     * Check whether a key exists in the array.\n     *\n     * @param key The key to search for.\n     * @return Returns true if the key exists, else false.\n     */\n    public boolean containsKey(Object key) {\n        return indexOfKey(key) >= 0;\n    }\n\n    /**\n     * Returns the index of a key in the set.\n     *\n     * @param key The key to search for.\n     * @return Returns the index of the key if it exists, else a negative integer.\n     */\n    public int indexOfKey(Object key) {\n        return key == null ? indexOfNull() : indexOf(key, key.hashCode());\n    }\n\n    int indexOfValue(Object value) {\n        final int N = mSize*2;\n        final Object[] array = mArray;\n        if (value == null) {\n            for (int i=1; i<N; i+=2) {\n                if (array[i] == null) {\n                    return i>>1;\n                }\n            }\n        } else {\n            for (int i=1; i<N; i+=2) {\n                if (value.equals(array[i])) {\n                    return i>>1;\n                }\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * Check whether a value exists in the array.  This requires a linear search\n     * through the entire array.\n     *\n     * @param value The value to search for.\n     * @return Returns true if the value exists, else false.\n     */\n    public boolean containsValue(Object value) {\n        return indexOfValue(value) >= 0;\n    }\n\n    /**\n     * Retrieve a value from the array.\n     * @param key The key of the value to retrieve.\n     * @return Returns the value associated with the given key,\n     * or null if there is no such key.\n     */\n    public V get(Object key) {\n        final int index = indexOfKey(key);\n        return index >= 0 ? (V)mArray[(index<<1)+1] : null;\n    }\n\n    /**\n     * Return the key at the given index in the array.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @return Returns the key stored at the given index.\n     */\n    public K keyAt(int index) {\n        return (K)mArray[index << 1];\n    }\n\n    /**\n     * Return the value at the given index in the array.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @return Returns the value stored at the given index.\n     */\n    public V valueAt(int index) {\n        return (V)mArray[(index << 1) + 1];\n    }\n\n    /**\n     * Set the value at a given index in the array.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @param value The new value to store at this index.\n     * @return Returns the previous value at the given index.\n     */\n    public V setValueAt(int index, V value) {\n        index = (index << 1) + 1;\n        V old = (V)mArray[index];\n        mArray[index] = value;\n        return old;\n    }\n\n    /**\n     * Return true if the array map contains no items.\n     */\n    public boolean isEmpty() {\n        return mSize <= 0;\n    }\n\n    /**\n     * Add a new value to the array map.\n     * @param key The key under which to store the value.  <b>Must not be null.</b>  If\n     * this key already exists in the array, its value will be replaced.\n     * @param value The value to store for the given key.\n     * @return Returns the old value that was stored for the given key, or null if there\n     * was no such key.\n     */\n    public V put(K key, V value) {\n        final int hash;\n        int index;\n        if (key == null) {\n            hash = 0;\n            index = indexOfNull();\n        } else {\n            hash = key.hashCode();\n            index = indexOf(key, hash);\n        }\n        if (index >= 0) {\n            index = (index<<1) + 1;\n            final V old = (V)mArray[index];\n            mArray[index] = value;\n            return old;\n        }\n\n        index = ~index;\n        if (mSize >= mHashes.length) {\n            final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))\n                    : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);\n\n            if (DEBUG) Log.d(TAG, \"put: grow from \" + mHashes.length + \" to \" + n);\n\n            final int[] ohashes = mHashes;\n            final Object[] oarray = mArray;\n            allocArrays(n);\n\n            if (mHashes.length > 0) {\n                if (DEBUG) Log.d(TAG, \"put: copy 0-\" + mSize + \" to 0\");\n                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);\n                System.arraycopy(oarray, 0, mArray, 0, oarray.length);\n            }\n\n            freeArrays(ohashes, oarray, mSize);\n        }\n\n        if (index < mSize) {\n            if (DEBUG) Log.d(TAG, \"put: move \" + index + \"-\" + (mSize-index)\n                    + \" to \" + (index+1));\n            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);\n            System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);\n        }\n\n        mHashes[index] = hash;\n        mArray[index<<1] = key;\n        mArray[(index<<1)+1] = value;\n        mSize++;\n        return null;\n    }\n\n    /**\n     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var>\n     * @param array The array whose contents are to be retrieved.\n     */\n    public void putAll(SimpleArrayMap<? extends K, ? extends V> array) {\n        final int N = array.mSize;\n        ensureCapacity(mSize + N);\n        if (mSize == 0) {\n            if (N > 0) {\n                System.arraycopy(array.mHashes, 0, mHashes, 0, N);\n                System.arraycopy(array.mArray, 0, mArray, 0, N<<1);\n                mSize = N;\n            }\n        } else {\n            for (int i=0; i<N; i++) {\n                put(array.keyAt(i), array.valueAt(i));\n            }\n        }\n    }\n\n    /**\n     * Remove an existing key from the array map.\n     * @param key The key of the mapping to remove.\n     * @return Returns the value that was stored under the key, or null if there\n     * was no such key.\n     */\n    public V remove(Object key) {\n        final int index = indexOfKey(key);\n        if (index >= 0) {\n            return removeAt(index);\n        }\n\n        return null;\n    }\n\n    /**\n     * Remove the key/value mapping at the given index.\n     * @param index The desired index, must be between 0 and {@link #size()}-1.\n     * @return Returns the value that was stored at this index.\n     */\n    public V removeAt(int index) {\n        final Object old = mArray[(index << 1) + 1];\n        if (mSize <= 1) {\n            // Now empty.\n            if (DEBUG) Log.d(TAG, \"remove: shrink from \" + mHashes.length + \" to 0\");\n            freeArrays(mHashes, mArray, mSize);\n            mHashes = ContainerHelpers.EMPTY_INTS;\n            mArray = ContainerHelpers.EMPTY_OBJECTS;\n            mSize = 0;\n        } else {\n            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {\n                // Shrunk enough to reduce size of arrays.  We don't allow it to\n                // shrink smaller than (BASE_SIZE*2) to avoid flapping between\n                // that and BASE_SIZE.\n                final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2);\n\n                if (DEBUG) Log.d(TAG, \"remove: shrink from \" + mHashes.length + \" to \" + n);\n\n                final int[] ohashes = mHashes;\n                final Object[] oarray = mArray;\n                allocArrays(n);\n\n                mSize--;\n                if (index > 0) {\n                    if (DEBUG) Log.d(TAG, \"remove: copy from 0-\" + index + \" to 0\");\n                    System.arraycopy(ohashes, 0, mHashes, 0, index);\n                    System.arraycopy(oarray, 0, mArray, 0, index << 1);\n                }\n                if (index < mSize) {\n                    if (DEBUG) Log.d(TAG, \"remove: copy from \" + (index+1) + \"-\" + mSize\n                            + \" to \" + index);\n                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);\n                    System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,\n                            (mSize - index) << 1);\n                }\n            } else {\n                mSize--;\n                if (index < mSize) {\n                    if (DEBUG) Log.d(TAG, \"remove: move \" + (index+1) + \"-\" + mSize\n                            + \" to \" + index);\n                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);\n                    System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,\n                            (mSize - index) << 1);\n                }\n                mArray[mSize << 1] = null;\n                mArray[(mSize << 1) + 1] = null;\n            }\n        }\n        return (V)old;\n    }\n\n    /**\n     * Return the number of items in this array map.\n     */\n    public int size() {\n        return mSize;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * <p>This implementation returns false if the object is not a map, or\n     * if the maps have different sizes. Otherwise, for each key in this map,\n     * values of both maps are compared. If the values for any key are not\n     * equal, the method returns false, otherwise it returns true.\n     */\n    @Override\n    public boolean equals(Object object) {\n        if (this == object) {\n            return true;\n        }\n        if (object instanceof Map) {\n            Map<?, ?> map = (Map<?, ?>) object;\n            if (size() != map.size()) {\n                return false;\n            }\n\n            try {\n                for (int i=0; i<mSize; i++) {\n                    K key = keyAt(i);\n                    V mine = valueAt(i);\n                    Object theirs = map.get(key);\n                    if (mine == null) {\n                        if (theirs != null || !map.containsKey(key)) {\n                            return false;\n                        }\n                    } else if (!mine.equals(theirs)) {\n                        return false;\n                    }\n                }\n            } catch (NullPointerException ignored) {\n                return false;\n            } catch (ClassCastException ignored) {\n                return false;\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int hashCode() {\n        final int[] hashes = mHashes;\n        final Object[] array = mArray;\n        int result = 0;\n        for (int i = 0, v = 1, s = mSize; i < s; i++, v+=2) {\n            Object value = array[v];\n            result += hashes[i] ^ (value == null ? 0 : value.hashCode());\n        }\n        return result;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * <p>This implementation composes a string by iterating over its mappings. If\n     * this map contains itself as a key or a value, the string \"(this Map)\"\n     * will appear in its place.\n     */\n    @Override\n    public String toString() {\n        if (isEmpty()) {\n            return \"{}\";\n        }\n\n        StringBuilder buffer = new StringBuilder(mSize * 28);\n        buffer.append('{');\n        for (int i=0; i<mSize; i++) {\n            if (i > 0) {\n                buffer.append(\", \");\n            }\n            Object key = keyAt(i);\n            if (key != this) {\n                buffer.append(key);\n            } else {\n                buffer.append(\"(this Map)\");\n            }\n            buffer.append('=');\n            Object value = valueAt(i);\n            if (value != this) {\n                buffer.append(value);\n            } else {\n                buffer.append(\"(this Map)\");\n            }\n        }\n        buffer.append('}');\n        return buffer.toString();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/collection/SparseArray.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.collection;\n\n/**\n * A copy of the current platform (currently {@link android.os.Build.VERSION_CODES#KITKAT}\n * version of {@link android.util.SparseArray}; provides a removeAt() method and other things.\n */\npublic class SparseArray<E> implements Cloneable {\n    private static final Object DELETED = new Object();\n    private boolean mGarbage = false;\n\n    private int[] mKeys;\n    private Object[] mValues;\n    private int mSize;\n\n    /**\n     * Creates a new SparseArray containing no mappings.\n     */\n    public SparseArray() {\n        this(10);\n    }\n\n    /**\n     * Creates a new SparseArray containing no mappings that will not\n     * require any additional memory allocation to store the specified\n     * number of mappings.  If you supply an initial capacity of 0, the\n     * sparse array will be initialized with a light-weight representation\n     * not requiring any additional array allocations.\n     */\n    public SparseArray(int initialCapacity) {\n        if (initialCapacity == 0) {\n            mKeys =  ContainerHelpers.EMPTY_INTS;\n            mValues =  ContainerHelpers.EMPTY_OBJECTS;\n        } else {\n            initialCapacity =  ContainerHelpers.idealIntArraySize(initialCapacity);\n            mKeys = new int[initialCapacity];\n            mValues = new Object[initialCapacity];\n        }\n        mSize = 0;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public SparseArray<E> clone() {\n        SparseArray<E> clone = null;\n        try {\n            clone = (SparseArray<E>) super.clone();\n            clone.mKeys = mKeys.clone();\n            clone.mValues = mValues.clone();\n        } catch (CloneNotSupportedException cnse) {\n            /* ignore */\n        }\n        return clone;\n    }\n\n    /**\n     * Gets the Object mapped from the specified key, or <code>null</code>\n     * if no such mapping has been made.\n     */\n    public E get(int key) {\n        return get(key, null);\n    }\n\n    /**\n     * Gets the Object mapped from the specified key, or the specified Object\n     * if no such mapping has been made.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public E get(int key, E valueIfKeyNotFound) {\n        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);\n\n        if (i < 0 || mValues[i] == DELETED) {\n            return valueIfKeyNotFound;\n        } else {\n            return (E) mValues[i];\n        }\n    }\n\n    /**\n     * Removes the mapping from the specified key, if there was any.\n     */\n    public void delete(int key) {\n        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);\n\n        if (i >= 0) {\n            if (mValues[i] != DELETED) {\n                mValues[i] = DELETED;\n                mGarbage = true;\n            }\n        }\n    }\n\n    /**\n     * Alias for {@link #delete(int)}.\n     */\n    public void remove(int key) {\n        delete(key);\n    }\n\n    /**\n     * Removes the mapping at the specified index.\n     */\n    public void removeAt(int index) {\n        if (mValues[index] != DELETED) {\n            mValues[index] = DELETED;\n            mGarbage = true;\n        }\n    }\n\n    /**\n     * Remove a range of mappings as a batch.\n     *\n     * @param index Index to begin at\n     * @param size Number of mappings to remove\n     */\n    public void removeAtRange(int index, int size) {\n        final int end = Math.min(mSize, index + size);\n        for (int i = index; i < end; i++) {\n            removeAt(i);\n        }\n    }\n\n    private void gc() {\n        // Log.e(\"SparseArray\", \"gc start with \" + mSize);\n\n        int n = mSize;\n        int o = 0;\n        int[] keys = mKeys;\n        Object[] values = mValues;\n\n        for (int i = 0; i < n; i++) {\n            Object val = values[i];\n\n            if (val != DELETED) {\n                if (i != o) {\n                    keys[o] = keys[i];\n                    values[o] = val;\n                    values[i] = null;\n                }\n\n                o++;\n            }\n        }\n\n        mGarbage = false;\n        mSize = o;\n\n        // Log.e(\"SparseArray\", \"gc end with \" + mSize);\n    }\n\n    /**\n     * Adds a mapping from the specified key to the specified value,\n     * replacing the previous mapping from the specified key if there\n     * was one.\n     */\n    public void put(int key, E value) {\n        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);\n\n        if (i >= 0) {\n            mValues[i] = value;\n        } else {\n            i = ~i;\n\n            if (i < mSize && mValues[i] == DELETED) {\n                mKeys[i] = key;\n                mValues[i] = value;\n                return;\n            }\n\n            if (mGarbage && mSize >= mKeys.length) {\n                gc();\n\n                // Search again because indices may have changed.\n                i = ~ ContainerHelpers.binarySearch(mKeys, mSize, key);\n            }\n\n            if (mSize >= mKeys.length) {\n                int n =  ContainerHelpers.idealIntArraySize(mSize + 1);\n\n                int[] nkeys = new int[n];\n                Object[] nvalues = new Object[n];\n\n                // Log.e(\"SparseArray\", \"grow \" + mKeys.length + \" to \" + n);\n                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);\n                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);\n\n                mKeys = nkeys;\n                mValues = nvalues;\n            }\n\n            if (mSize - i != 0) {\n                // Log.e(\"SparseArray\", \"move \" + (mSize - i));\n                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);\n                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);\n            }\n\n            mKeys[i] = key;\n            mValues[i] = value;\n            mSize++;\n        }\n    }\n\n    /**\n     * Returns the number of key-value mappings that this SparseArray\n     * currently stores.\n     */\n    public int size() {\n        if (mGarbage) {\n            gc();\n        }\n\n        return mSize;\n    }\n\n    /**\n     * Given an index in the range <code>0...size()-1</code>, returns\n     * the key from the <code>index</code>th key-value mapping that this\n     * SparseArray stores.\n     */\n    public int keyAt(int index) {\n        if (mGarbage) {\n            gc();\n        }\n\n        return mKeys[index];\n    }\n\n    /**\n     * Given an index in the range <code>0...size()-1</code>, returns\n     * the value from the <code>index</code>th key-value mapping that this\n     * SparseArray stores.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public E valueAt(int index) {\n        if (mGarbage) {\n            gc();\n        }\n\n        return (E) mValues[index];\n    }\n\n    /**\n     * @hide\n     * Removes the mapping from the specified key, if there was any, returning the old value.\n     */\n    public E removeReturnOld(int key) {\n        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);\n\n        if (i >= 0) {\n            if (mValues[i] != DELETED) {\n                final E old = (E) mValues[i];\n                mValues[i] = DELETED;\n                mGarbage = true;\n                return old;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Given an index in the range <code>0...size()-1</code>, sets a new\n     * value for the <code>index</code>th key-value mapping that this\n     * SparseArray stores.\n     */\n    public void setValueAt(int index, E value) {\n        if (mGarbage) {\n            gc();\n        }\n\n        mValues[index] = value;\n    }\n\n    /**\n     * Returns the index for which {@link #keyAt} would return the\n     * specified key, or a negative number if the specified\n     * key is not mapped.\n     */\n    public int indexOfKey(int key) {\n        if (mGarbage) {\n            gc();\n        }\n\n        return  ContainerHelpers.binarySearch(mKeys, mSize, key);\n    }\n\n    /**\n     * Returns an index for which {@link #valueAt} would return the\n     * specified key, or a negative number if no keys map to the\n     * specified value.\n     * <p>Beware that this is a linear search, unlike lookups by key,\n     * and that multiple keys can map to the same value and this will\n     * find only one of them.\n     * <p>Note also that unlike most collections' {@code indexOf} methods,\n     * this method compares values using {@code ==} rather than {@code equals}.\n     */\n    public int indexOfValue(E value) {\n        if (mGarbage) {\n            gc();\n        }\n\n        for (int i = 0; i < mSize; i++)\n            if (mValues[i] == value)\n                return i;\n\n        return -1;\n    }\n\n    /**\n     * Removes all key-value mappings from this SparseArray.\n     */\n    public void clear() {\n        int n = mSize;\n        Object[] values = mValues;\n\n        for (int i = 0; i < n; i++) {\n            values[i] = null;\n        }\n\n        mSize = 0;\n        mGarbage = false;\n    }\n\n    /**\n     * Puts a key/value pair into the array, optimizing for the case where\n     * the key is greater than all existing keys in the array.\n     */\n    public void append(int key, E value) {\n        if (mSize != 0 && key <= mKeys[mSize - 1]) {\n            put(key, value);\n            return;\n        }\n\n        if (mGarbage && mSize >= mKeys.length) {\n            gc();\n        }\n\n        int pos = mSize;\n        if (pos >= mKeys.length) {\n            int n =  ContainerHelpers.idealIntArraySize(pos + 1);\n\n            int[] nkeys = new int[n];\n            Object[] nvalues = new Object[n];\n\n            // Log.e(\"SparseArray\", \"grow \" + mKeys.length + \" to \" + n);\n            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);\n            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);\n\n            mKeys = nkeys;\n            mValues = nvalues;\n        }\n\n        mKeys[pos] = key;\n        mValues[pos] = value;\n        mSize = pos + 1;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * <p>This implementation composes a string by iterating over its mappings. If\n     * this map contains itself as a value, the string \"(this Map)\"\n     * will appear in its place.\n     */\n    @Override\n    public String toString() {\n        if (size() <= 0) {\n            return \"{}\";\n        }\n\n        StringBuilder buffer = new StringBuilder(mSize * 28);\n        buffer.append('{');\n        for (int i=0; i<mSize; i++) {\n            if (i > 0) {\n                buffer.append(\", \");\n            }\n            int key = keyAt(i);\n            buffer.append(key);\n            buffer.append('=');\n            Object value = valueAt(i);\n            if (value != this) {\n                buffer.append(value);\n            } else {\n                buffer.append(\"(this Map)\");\n            }\n        }\n        buffer.append('}');\n        return buffer.toString();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/AccountManagerCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.accounts.AccountManager;\n\n/**\n * @author Lody\n */\n\npublic class AccountManagerCompat {\n\n    /**\n     * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the\n     * associated auth token.\n     *\n     */\n    public static final String KEY_CUSTOM_TOKEN_EXPIRY = \"android.accounts.expiry\";\n\n    /**\n     * Bundle key used to supply the last time the credentials of the account\n     * were authenticated successfully. Time is specified in milliseconds since\n     * epoch. Associated time is updated on successful authentication of account\n     * on adding account, confirming credentials, or updating credentials.\n     */\n    public static final String KEY_LAST_AUTHENTICATED_TIME = \"lastAuthenticatedTime\";\n\n    /**\n     * Boolean, if set and 'customTokens' the authenticator is responsible for\n     * notifications.\n     */\n    public static final String KEY_NOTIFY_ON_FAILURE = \"notifyOnAuthFailure\";\n\n    /**\n     * The Android package of the caller will be set in the options bundle by the\n     * {@link AccountManager} and will be passed to the AccountManagerService and\n     * to the AccountAuthenticators. The vuid of the caller will be known by the\n     * AccountManagerService as well as the AccountAuthenticators so they will be able to\n     * verify that the package is consistent with the vuid (a vuid might be shared by many\n     * packages).\n     */\n    public static final String KEY_ANDROID_PACKAGE_NAME = \"androidPackageName\";\n\n    public static final int ERROR_CODE_USER_RESTRICTED = 100;\n\n    public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ActivityManagerCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.IBinder;\n\nimport mirror.android.app.ActivityManagerNative;\nimport mirror.android.app.IActivityManagerICS;\nimport mirror.android.app.IActivityManagerL;\nimport mirror.android.app.IActivityManagerN;\n\n/**\n * @author Lody\n */\n\npublic class ActivityManagerCompat {\n\t/** Type for IActivityManager.serviceDoneExecuting: anonymous operation */\n\tpublic static final int SERVICE_DONE_EXECUTING_ANON = 0;\n\t/** Type for IActivityManager.serviceDoneExecuting: done with an onStart call */\n\tpublic static final int SERVICE_DONE_EXECUTING_START = 1;\n\t/** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */\n\tpublic static final int SERVICE_DONE_EXECUTING_STOP = 2;\n\n\t/**\n\t * Result for IActivityManager.startActivity: an error where the\n\t * given Intent could not be resolved to an activity.\n\t */\n\tpublic static final int START_INTENT_NOT_RESOLVED = -1;\n\n\t/**\n\t * Result for IActivityManager.startActivity: trying to start a background user\n\t * activity that shouldn't be displayed for all users.\n\t */\n\tpublic static final int START_NOT_CURRENT_USER_ACTIVITY = -8;\n\n\t/**\n\t * Result for IActivityManaqer.startActivity: activity wasn't really started, but\n\t * a task was simply brought to the foreground.\n\t */\n\tpublic static final int START_TASK_TO_FRONT = 2;\n\n\t/**\n\t * Type for IActivityManaqer.getIntentSender: this PendingIntent is\n\t * for a sendBroadcast operation.\n\t */\n\tpublic static final int INTENT_SENDER_BROADCAST = 1;\n\n\t/**\n\t * Type for IActivityManaqer.getIntentSender: this PendingIntent is\n\t * for a startActivity operation.\n\t */\n\tpublic static final int INTENT_SENDER_ACTIVITY = 2;\n\n\t/**\n\t * Type for IActivityManaqer.getIntentSender: this PendingIntent is\n\t * for an activity result operation.\n\t */\n\tpublic static final int INTENT_SENDER_ACTIVITY_RESULT = 3;\n\n\t/**\n\t * Type for IActivityManaqer.getIntentSender: this PendingIntent is\n\t * for a startService operation.\n\t */\n\tpublic static final int INTENT_SENDER_SERVICE = 4;\n\n\t/** User operation call: success! */\n\tpublic static final int USER_OP_SUCCESS = 0;\n\n\tpublic static boolean finishActivity(IBinder token, int code, Intent data) {\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n\t\t\treturn IActivityManagerN.finishActivity.call(\n\t\t\t\t\tActivityManagerNative.getDefault.call(),\n\t\t\t\t\ttoken, code, data, 0);\n\t\t} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n\t\t\treturn IActivityManagerL.finishActivity.call(\n\t\t\t\t\t\tActivityManagerNative.getDefault.call(),\n\t\t\t\t\t\ttoken, code, data, false);\n\t\t} else {\n\t\t\tIActivityManagerICS.finishActivity.call(\n\t\t\t\t\tActivityManagerNative.getDefault.call(),\n\t\t\t\t\ttoken, code, data\n\t\t\t);\n\t\t}\n\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ApplicationThreadCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.android.app.ApplicationThreadNative;\nimport mirror.android.app.IApplicationThreadOreo;\n\n/**\n * @author Lody\n */\n\npublic class ApplicationThreadCompat {\n\n    public static IInterface asInterface(IBinder binder) {\n        if (BuildCompat.isOreo()) {\n            return IApplicationThreadOreo.Stub.asInterface.call(binder);\n        }\n        return ApplicationThreadNative.asInterface.call(binder);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/BuildCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.os.Build;\n\n/**\n * @author Lody\n */\n\npublic class BuildCompat {\n\n    public static int getPreviewSDKInt() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                return Build.VERSION.PREVIEW_SDK_INT;\n            } catch (Throwable e) {\n                // ignore\n            }\n        }\n        return 0;\n    }\n\n    public static boolean isOreo() {\n        return isAndroidLevel(Build.VERSION_CODES.O);\n    }\n\n    public static boolean isPie() {\n        return isAndroidLevel(Build.VERSION_CODES.P);\n    }\n\n    public static boolean isQ() {\n        return isAndroidLevel(29);\n    }\n\n    public static boolean isR() {\n        return isAndroidLevel(30);\n    }\n\n    public static boolean isS() {\n        return isAndroidLevel(31);\n    }\n\n    private static boolean isAndroidLevelPreview(int level) {\n        return (Build.VERSION.SDK_INT == level && getPreviewSDKInt() > 0)\n                || Build.VERSION.SDK_INT > level;\n    }\n\n    private static boolean isAndroidLevel(int level) {\n        return Build.VERSION.SDK_INT >= level;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/BundleCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\n\nimport mirror.android.os.BaseBundle;\nimport mirror.android.os.BundleICS;\n\n/**\n * @author Lody\n */\npublic class BundleCompat {\n    public static IBinder getBinder(Bundle bundle, String key) {\n        if (Build.VERSION.SDK_INT >= 18) {\n            return bundle.getBinder(key);\n        } else {\n            return mirror.android.os.Bundle.getIBinder.call(bundle, key);\n        }\n    }\n\n    public static void putBinder(Bundle bundle, String key, IBinder value) {\n        if (Build.VERSION.SDK_INT >= 18) {\n            bundle.putBinder(key, value);\n        } else {\n            mirror.android.os.Bundle.putIBinder.call(bundle, key, value);\n        }\n    }\n\n    public static void clearParcelledData(Bundle bundle) {\n        Parcel obtain = Parcel.obtain();\n        obtain.writeInt(0);\n        obtain.setDataPosition(0);\n        Parcel parcel;\n        if (BaseBundle.TYPE != null) {\n            parcel = BaseBundle.mParcelledData.get(bundle);\n            if (parcel != null) {\n                parcel.recycle();\n            }\n            BaseBundle.mParcelledData.set(bundle, obtain);\n        } else if (BundleICS.TYPE != null) {\n            parcel = BundleICS.mParcelledData.get(bundle);\n            if (parcel != null) {\n                parcel.recycle();\n            }\n            BundleICS.mParcelledData.set(bundle, obtain);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ContentProviderCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.content.ContentProviderClient;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Build.VERSION;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\n\n/**\n * @author Lody\n */\npublic class ContentProviderCompat {\n\n    public static Bundle call(Context context, Uri uri, String method, String arg, Bundle extras) {\n        if (VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            return context.getContentResolver().call(uri, method, arg, extras);\n        }\n        ContentProviderClient client = crazyAcquireContentProvider(context, uri);\n        Bundle res = null;\n        try {\n            res = client.call(method, arg, extras);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        } finally {\n            releaseQuietly(client);\n        }\n        return res;\n    }\n\n\n    private static ContentProviderClient acquireContentProviderClient(Context context, Uri uri) {\n        if (VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return context.getContentResolver().acquireUnstableContentProviderClient(uri);\n        }\n        return context.getContentResolver().acquireContentProviderClient(uri);\n    }\n\n    public static ContentProviderClient crazyAcquireContentProvider(Context context, Uri uri) {\n        ContentProviderClient client = acquireContentProviderClient(context, uri);\n        if (client == null) {\n            int retry = 0;\n            while (retry < 5 && client == null) {\n                SystemClock.sleep(100);\n                retry++;\n                client = acquireContentProviderClient(context, uri);\n            }\n        }\n        return client;\n    }\n\n    public static ContentProviderClient crazyAcquireContentProvider(Context context, String name) {\n        ContentProviderClient client = acquireContentProviderClient(context, name);\n        if (client == null) {\n            int retry = 0;\n            while (retry < 5 && client == null) {\n                SystemClock.sleep(100);\n                retry++;\n                client = acquireContentProviderClient(context, name);\n            }\n        }\n        return client;\n    }\n\n    private static ContentProviderClient acquireContentProviderClient(Context context, String name) {\n        if (VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            return context.getContentResolver().acquireUnstableContentProviderClient(name);\n        }\n        return context.getContentResolver().acquireContentProviderClient(name);\n    }\n\n    public static void releaseQuietly(ContentProviderClient client) {\n        if (client != null) {\n            try {\n                if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    client.close();\n                } else {\n                    client.release();\n                }\n            } catch (Exception ignored) {\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ContentResolverCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\n/**\n * @author Lody\n */\n\npublic class ContentResolverCompat {\n\n    public static final int SYNC_OBSERVER_TYPE_STATUS = 1 << 3;\n\n    \n    public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;\n    \n    public static final int SYNC_ERROR_AUTHENTICATION = 2;\n    \n    public static final int SYNC_ERROR_IO = 3;\n    \n    public static final int SYNC_ERROR_PARSE = 4;\n    \n    public static final int SYNC_ERROR_CONFLICT = 5;\n    \n    public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;\n    \n    public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;\n    \n    public static final int SYNC_ERROR_INTERNAL = 8;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/IApplicationThreadCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport mirror.android.app.IApplicationThread;\nimport mirror.android.app.IApplicationThreadICSMR1;\nimport mirror.android.app.IApplicationThreadKitkat;\nimport mirror.android.app.IApplicationThreadOreo;\nimport mirror.android.app.ServiceStartArgs;\nimport mirror.android.content.res.CompatibilityInfo;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThreadCompat {\n\n    public static void scheduleCreateService(IInterface appThread, IBinder token, ServiceInfo info,\n                                             int processState) throws RemoteException {\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            IApplicationThreadKitkat.scheduleCreateService.call(appThread, token, info, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO.get(),\n                    processState);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n            IApplicationThreadICSMR1.scheduleCreateService.call(appThread, token, info, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO.get());\n        } else {\n            IApplicationThread.scheduleCreateService.call(appThread, token, info);\n        }\n\n    }\n\n    public static void scheduleBindService(IInterface appThread, IBinder token, Intent intent, boolean rebind,\n                                           int processState) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            IApplicationThreadKitkat.scheduleBindService.call(appThread, token, intent, rebind, processState);\n        } else {\n            IApplicationThread.scheduleBindService.call(appThread, token, intent, rebind);\n        }\n    }\n\n    public static void scheduleUnbindService(IInterface appThread, IBinder token, Intent intent) throws RemoteException {\n        IApplicationThread.scheduleUnbindService.call(appThread, token, intent);\n    }\n\n    public static void scheduleServiceArgs(IInterface appThread, IBinder token, boolean taskRemoved,\n                                           int startId, int flags, Intent args) throws RemoteException {\n\n        if (Build.VERSION.SDK_INT >= 26) {\n            List<Object> list = new ArrayList<>(1);\n            Object serviceStartArg = ServiceStartArgs.ctor.newInstance(taskRemoved, startId, flags, args);\n            list.add(serviceStartArg);\n            IApplicationThreadOreo.scheduleServiceArgs.call(appThread, token, ParceledListSliceCompat.create(list));\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n            IApplicationThreadICSMR1.scheduleServiceArgs.call(appThread, token, taskRemoved, startId, flags, args);\n        } else {\n            IApplicationThread.scheduleServiceArgs.call(appThread, token, startId, flags, args);\n        }\n    }\n\n\n    public static void scheduleStopService(IInterface appThread, IBinder token) throws RemoteException {\n        IApplicationThread.scheduleStopService.call(appThread, token);\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/NativeLibraryHelperCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.SystemClock;\n\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport mirror.com.android.internal.content.NativeLibraryHelper;\nimport mirror.dalvik.system.VMRuntime;\n\npublic class NativeLibraryHelperCompat {\n\n\tprivate static String TAG = NativeLibraryHelperCompat.class.getSimpleName();\n\n\tpublic static int copyNativeBinaries(File apkFile, File sharedLibraryDir) {\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n\t\t\treturn copyNativeBinariesAfterL(apkFile, sharedLibraryDir);\n\t\t} else {\n\t\t\treturn copyNativeBinariesBeforeL(apkFile, sharedLibraryDir);\n\t\t}\n\t}\n\n\tprivate static int copyNativeBinariesBeforeL(File apkFile, File sharedLibraryDir) {\n\t\ttry {\n\t\t\treturn Reflect.on(NativeLibraryHelper.TYPE).call(\"copyNativeBinariesIfNeededLI\", apkFile, sharedLibraryDir)\n\t\t\t\t\t.get();\n\t\t} catch (Throwable e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn -1;\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\tprivate static int copyNativeBinariesAfterL(File apkFile, File sharedLibraryDir) {\n\t\ttry {\n\t\t\tObject handle = NativeLibraryHelper.Handle.create.call(apkFile);\n\t\t\tif (handle == null) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tString abi = null;\n\t\t\tSet<String> abiSet = getABIsFromApk(apkFile.getAbsolutePath());\n\t\t\tif (abiSet == null || abiSet.isEmpty()) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tboolean is64Bit = VMRuntime.is64Bit.call(VMRuntime.getRuntime.call());\n\t\t\tif (is64Bit && isVM64(abiSet)) {\n\t\t\t\tif (Build.SUPPORTED_64_BIT_ABIS.length > 0) {\n\t\t\t\t\tint abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_64_BIT_ABIS);\n\t\t\t\t\tif (abiIndex >= 0) {\n\t\t\t\t\t\tabi = Build.SUPPORTED_64_BIT_ABIS[abiIndex];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Build.SUPPORTED_32_BIT_ABIS.length > 0) {\n\t\t\t\t\tint abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_32_BIT_ABIS);\n\t\t\t\t\tif (abiIndex >= 0) {\n\t\t\t\t\t\tabi = Build.SUPPORTED_32_BIT_ABIS[abiIndex];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (abi == null) {\n\t\t\t\tVLog.e(TAG, \"Not match any abi [%s].\", apkFile.getPath());\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn NativeLibraryHelper.copyNativeBinaries.call(handle, sharedLibraryDir, abi);\n\t\t} catch (Throwable e) {\n\t\t\tVLog.d(TAG, \"copyNativeBinaries with error : %s\", e.getLocalizedMessage());\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t@TargetApi(Build.VERSION_CODES.LOLLIPOP)\n\tprivate static boolean isVM64(Set<String> supportedABIs) {\n\t\tif (Build.SUPPORTED_64_BIT_ABIS.length == 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (supportedABIs == null || supportedABIs.isEmpty()) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (String supportedAbi : supportedABIs) {\n\t\t\tif (\"arm64-v8a\".endsWith(supportedAbi) || \"x86_64\".equals(supportedAbi) || \"mips64\".equals(supportedAbi)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate static Set<String> getABIsFromApk(String apk) {\n\t\ttry (ZipFile apkFile = new ZipFile(apk)) {\n\t\t\tEnumeration<? extends ZipEntry> entries = apkFile.entries();\n\t\t\tSet<String> supportedABIs = new HashSet<String>();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tZipEntry entry = entries.nextElement();\n\t\t\t\tString name = entry.getName();\n\t\t\t\tif (name.contains(\"../\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (name.startsWith(\"lib/\") && !entry.isDirectory() && name.endsWith(\".so\")) {\n\t\t\t\t\tString supportedAbi = name.substring(name.indexOf(\"/\") + 1, name.lastIndexOf(\"/\"));\n\t\t\t\t\tsupportedABIs.add(supportedAbi);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn supportedABIs;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic static boolean isApk64(String apk) {\n\t\tlong start = SystemClock.elapsedRealtime();\n\t\tSet<String> abIsFromApk = getABIsFromApk(apk);\n\t\tSystem.out.println(\"pkg: \" + apk + \" abis: \" + abIsFromApk + \" cost: \" + (SystemClock.elapsedRealtime() - start));\n\t\treturn isVM64(abIsFromApk);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ObjectsCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\n/**\n * @author Lody\n */\n\npublic class ObjectsCompat {\n\n\t/**\n\t * Null-safe equivalent of {@code a.equals(b)}.\n\t */\n\tpublic static boolean equals(Object a, Object b) {\n\t\treturn (a == null) ? (b == null) : a.equals(b);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/PackageParserCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageParser;\nimport android.content.pm.PackageParser.Activity;\nimport android.content.pm.PackageParser.Package;\nimport android.content.pm.PackageParser.Provider;\nimport android.content.pm.PackageParser.Service;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\nimport android.os.Process;\nimport android.util.DisplayMetrics;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.os.VUserHandle;\n\nimport java.io.File;\n\nimport mirror.android.content.pm.PackageParserJellyBean;\nimport mirror.android.content.pm.PackageParserJellyBean17;\nimport mirror.android.content.pm.PackageParserLollipop;\nimport mirror.android.content.pm.PackageParserLollipop22;\nimport mirror.android.content.pm.PackageParserMarshmallow;\nimport mirror.android.content.pm.PackageParserNougat;\nimport mirror.android.content.pm.PackageParserP28;\nimport mirror.android.content.pm.PackageUserState;\n\nimport static android.os.Build.VERSION_CODES.JELLY_BEAN;\nimport static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;\nimport static android.os.Build.VERSION_CODES.M;\nimport static android.os.Build.VERSION_CODES.N;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserCompat {\n\n    public static final int[] GIDS = VirtualCore.get().getGids();\n    private static final int API_LEVEL = Build.VERSION.SDK_INT;\n    private static final int myUserId = VUserHandle.getUserId(Process.myUid());\n    private static final Object sUserState = API_LEVEL >= JELLY_BEAN_MR1 ? PackageUserState.ctor.newInstance() : null;\n\n\n    public static PackageParser createParser(File packageFile) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.ctor.newInstance();\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.ctor.newInstance();\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.ctor.newInstance();\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.ctor.newInstance(packageFile.getAbsolutePath());\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.ctor.newInstance(packageFile.getAbsolutePath());\n        } else {\n            return mirror.android.content.pm.PackageParser.ctor.newInstance(packageFile.getAbsolutePath());\n        }\n    }\n\n    public static Package parsePackage(PackageParser parser, File packageFile, int flags) throws Throwable {\n        if (BuildCompat.isQ()) {\n            PackageParserP28.setCallback.call(parser, PackageParserP28.CallbackImpl.ctor.newInstance(VirtualCore.getPM()));\n        }\n\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.parsePackage.callWithException(parser, packageFile, flags);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.parsePackage.callWithException(parser, packageFile, flags);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.parsePackage.callWithException(parser, packageFile, flags);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.parsePackage.callWithException(parser, packageFile, null,\n                    new DisplayMetrics(), flags);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.parsePackage.callWithException(parser, packageFile, null,\n                    new DisplayMetrics(), flags);\n        } else {\n            return mirror.android.content.pm.PackageParser.parsePackage.callWithException(parser, packageFile, null,\n                    new DisplayMetrics(), flags);\n        }\n    }\n\n    public static ServiceInfo generateServiceInfo(Service service, int flags) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.generateServiceInfo.call(service, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.generateServiceInfo.call(service, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.generateServiceInfo.call(service, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.generateServiceInfo.call(service, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.generateServiceInfo.call(service, flags, false, 1, myUserId);\n        } else {\n            return mirror.android.content.pm.PackageParser.generateServiceInfo.call(service, flags);\n        }\n    }\n\n    public static ApplicationInfo generateApplicationInfo(Package p, int flags) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.generateApplicationInfo.call(p, flags, sUserState);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.generateApplicationInfo.call(p, flags, sUserState);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.generateApplicationInfo.call(p, flags, sUserState);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.generateApplicationInfo.call(p, flags, sUserState);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.generateApplicationInfo.call(p, flags, false, 1);\n        } else {\n            return mirror.android.content.pm.PackageParser.generateApplicationInfo.call(p, flags);\n        }\n    }\n\n    public static ActivityInfo generateActivityInfo(Activity activity, int flags) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.generateActivityInfo.call(activity, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.generateActivityInfo.call(activity, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.generateActivityInfo.call(activity, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.generateActivityInfo.call(activity, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.generateActivityInfo.call(activity, flags, false, 1, myUserId);\n        } else {\n            return mirror.android.content.pm.PackageParser.generateActivityInfo.call(activity, flags);\n        }\n    }\n\n    public static ProviderInfo generateProviderInfo(Provider provider, int flags) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.generateProviderInfo.call(provider, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            return PackageParserLollipop22.generateProviderInfo.call(provider, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            return PackageParserLollipop.generateProviderInfo.call(provider, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.generateProviderInfo.call(provider, flags, sUserState, myUserId);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.generateProviderInfo.call(provider, flags, false, 1, myUserId);\n        } else {\n            return mirror.android.content.pm.PackageParser.generateProviderInfo.call(provider, flags);\n        }\n    }\n\n    public static PackageInfo generatePackageInfo(Package p, int flags, long firstInstallTime, long lastUpdateTime) {\n        if (API_LEVEL >= M) {\n            return PackageParserMarshmallow.generatePackageInfo.call(p, GIDS, flags, firstInstallTime, lastUpdateTime,\n                    null, sUserState);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            if (PackageParserLollipop22.generatePackageInfo != null) {\n                return PackageParserLollipop22.generatePackageInfo.call(p, GIDS, flags, firstInstallTime, lastUpdateTime,\n                        null, sUserState);\n            } else {\n                return PackageParserLollipop.generatePackageInfo.call(p, GIDS, flags, firstInstallTime, lastUpdateTime,\n                        null, sUserState);\n            }\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            return PackageParserJellyBean17.generatePackageInfo.call(p, GIDS, flags, firstInstallTime, lastUpdateTime,\n                    null, sUserState);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            return PackageParserJellyBean.generatePackageInfo.call(p, GIDS, flags, firstInstallTime, lastUpdateTime,\n                    null);\n        } else {\n            return mirror.android.content.pm.PackageParser.generatePackageInfo.call(p, GIDS, flags, firstInstallTime,\n                    lastUpdateTime);\n        }\n    }\n\n    public static void collectCertificates(PackageParser parser, Package p, int flags) throws Throwable {\n        if (API_LEVEL >= 28) {\n            PackageParserP28.collectCertificates.callWithException(p, true);\n        } else if (API_LEVEL >= N) {\n            PackageParserNougat.collectCertificates.callWithException(p, flags);\n        } else if (API_LEVEL >= M) {\n            PackageParserMarshmallow.collectCertificates.callWithException(parser, p, flags);\n        } else if (API_LEVEL >= LOLLIPOP_MR1) {\n            PackageParserLollipop22.collectCertificates.callWithException(parser, p, flags);\n        } else if (API_LEVEL >= LOLLIPOP) {\n            PackageParserLollipop.collectCertificates.callWithException(parser, p, flags);\n        } else if (API_LEVEL >= JELLY_BEAN_MR1) {\n            PackageParserJellyBean17.collectCertificates.callWithException(parser, p, flags);\n        } else if (API_LEVEL >= JELLY_BEAN) {\n            PackageParserJellyBean.collectCertificates.callWithException(parser, p, flags);\n        } else {\n            mirror.android.content.pm.PackageParser.collectCertificates.call(parser, p, flags);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/ParceledListSliceCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.List;\n\nimport mirror.android.content.pm.ParceledListSlice;\nimport mirror.android.content.pm.ParceledListSliceJBMR2;\n\n/**\n * @author Lody\n *\n */\npublic class ParceledListSliceCompat {\n\n\tpublic static boolean isReturnParceledListSlice(Method method) {\n\t\treturn method != null && method.getReturnType() == ParceledListSlice.TYPE;\n\t}\n\n\tpublic static  Object create(List list) {\n\t\tif (ParceledListSliceJBMR2.ctor != null) {\n\t\t\treturn ParceledListSliceJBMR2.ctor.newInstance(list);\n\t\t} else {\n\t\t\tObject slice = ParceledListSlice.ctor.newInstance();\n\t\t\tfor (Object item : list) {\n\t\t\t\tParceledListSlice.append.call(slice, item);\n\t\t\t}\n\t\t\tParceledListSlice.setLastSlice.call(slice, true);\n\t\t\treturn slice;\n\t\t}\n\t}\n\n\tpublic static List getList(Object parceledList) {\n\t\tif (parceledList == null || parceledList.getClass() != ParceledListSlice.TYPE) {\n\t\t\treturn Collections.EMPTY_LIST;\n\t\t}\n\n\t\tif (ParceledListSliceJBMR2.getList != null) {\n\t\t\treturn ParceledListSliceJBMR2.getList.call(parceledList);\n\t\t} else {\n\t\t\treturn ParceledListSlice.getList.call(parceledList);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/StorageManagerCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Environment;\nimport android.os.storage.StorageManager;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\n\npublic class StorageManagerCompat {\n\n    private StorageManagerCompat() {\n    }\n\n    public static String[] getAllPoints(Context context) {\n        StorageManager manager = (StorageManager)\n                context.getSystemService(Activity.STORAGE_SERVICE);\n        String[] points = null;\n        try {\n            Method method = manager.getClass().getMethod(\"getVolumePaths\");\n            points = (String[]) method.invoke(manager);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return points;\n    }\n\n    public static boolean isMounted(Context context, String point) {\n        if (point == null)\n            return false;\n        StorageManager manager = (StorageManager)\n                context.getSystemService(Activity.STORAGE_SERVICE);\n        try {\n            Method method = manager.getClass().getMethod(\"getVolumeState\", String.class);\n            String state = (String) method.invoke(manager, point);\n            return Environment.MEDIA_MOUNTED.equals(state);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    public static ArrayList<String> getMountedPoints(Context context) {\n        StorageManager manager = (StorageManager)\n                context.getSystemService(Activity.STORAGE_SERVICE);\n        ArrayList<String> mountedPoints = new ArrayList<String>();\n        try {\n            Method getVolumePaths = manager.getClass().getMethod(\"getVolumePaths\");\n            String[] points = (String[]) getVolumePaths.invoke(manager);\n            if (points != null && points.length > 0) {\n                Method getVolumeState = manager.getClass().getMethod(\"getVolumeState\", String.class);\n                for (String point : points) {\n                    String state = (String) getVolumeState.invoke(manager, point);\n                    if (Environment.MEDIA_MOUNTED.equals(state))\n                        mountedPoints.add(point);\n                }\n                return mountedPoints;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/SystemPropertiesCompat.java",
    "content": "package com.lody.virtual.helper.compat;\n\nimport com.lody.virtual.helper.utils.Reflect;\n\nimport java.lang.reflect.InvocationTargetException;\n\npublic class SystemPropertiesCompat {\n\n    private static Class<?> sClass;\n\n    public SystemPropertiesCompat() {\n    }\n\n    private static Class getSystemPropertiesClass() throws ClassNotFoundException {\n        if (sClass == null) {\n            sClass = Class.forName(\"android.os.SystemProperties\");\n        }\n        return sClass;\n    }\n\n    private static String getInner(String key, String defaultValue)\n            throws NoSuchMethodException, IllegalAccessException,\n            InvocationTargetException, ClassNotFoundException {\n        Class clazz = getSystemPropertiesClass();\n        return (String) Reflect.on(clazz).call(\"get\", key, defaultValue).get();\n    }\n\n    public static String get(String key, String defaultValue) {\n        try {\n            return getInner(key, defaultValue);\n        } catch (Exception var3) {\n            var3.printStackTrace();\n            return defaultValue;\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ArrayUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport com.lody.virtual.helper.compat.ObjectsCompat;\n\n/**\n * @author Lody\n *\n */\npublic class ArrayUtils {\n\n\tpublic static Object[] push(Object[] array, Object item)\n\t{\n\t\tObject[] longer = new Object[array.length + 1];\n\t\tSystem.arraycopy(array, 0, longer, 0, array.length);\n\t\tlonger[array.length] = item;\n\t\treturn longer;\n\t}\n\n\tpublic static <T> boolean contains(T[] array, T value) {\n\t\treturn indexOf(array, value) != -1;\n\t}\n\tpublic static boolean contains(int[] array, int value) {\n\t\tif (array == null) return false;\n\t\tfor (int element : array) {\n\t\t\tif (element == value) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return first index of {@code value} in {@code array}, or {@code -1} if\n\t * not found.\n\t */\n\tpublic static <T> int indexOf(T[] array, T value) {\n\t\tif (array == null) return -1;\n\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\tif (ObjectsCompat.equals(array[i], value)) return i;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tpublic static int protoIndexOf(Class<?>[] array, Class<?> type) {\n\t\tif (array == null) return -1;\n\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\tif (array[i] == type) return i;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tpublic static int indexOfFirst(Object[] array, Class<?> type) {\n\t\tif (!isEmpty(array)) {\n\t\t\tint N = -1;\n\t\t\tfor (Object one : array) {\n\t\t\t\tN++;\n\t\t\t\tif (one != null && type == one.getClass()) {\n\t\t\t\t\treturn N;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tpublic static int protoIndexOf(Class<?>[] array, Class<?> type, int sequence) {\n\t\tif (array == null) {\n\t\t\treturn -1;\n\t\t}\n\t\twhile (sequence < array.length) {\n\t\t\tif (type == array[sequence]) {\n\t\t\t\treturn sequence;\n\t\t\t}\n\t\t\tsequence++;\n\t\t}\n\t\treturn -1;\n\t}\n\n\n\tpublic static int indexOfObject(Object[] array, Class<?> type, int sequence) {\n\t\tif (array == null) {\n\t\t\treturn -1;\n\t\t}\n\t\twhile (sequence < array.length) {\n\t\t\tif (type.isInstance(array[sequence])) {\n\t\t\t\treturn sequence;\n\t\t\t}\n\t\t\tsequence++;\n\t\t}\n\t\treturn -1;\n\t}\n\n\n\tpublic static int indexOf(Object[] array, Class<?> type, int sequence) {\n\t\tif (!isEmpty(array)) {\n\t\t\tint N = -1;\n\t\t\tfor (Object one : array) {\n\t\t\t\tN++;\n\t\t\t\tif (one != null && one.getClass() == type) {\n\t\t\t\t\tif (--sequence <= 0) {\n\t\t\t\t\t\treturn N;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tpublic static int indexOfLast(Object[] array, Class<?> type) {\n\t\tif (!isEmpty(array)) {\n\t\t\tfor (int N = array.length; N > 0; N--) {\n\t\t\t\tObject one = array[N - 1];\n\t\t\t\tif (one != null && one.getClass() == type) {\n\t\t\t\t\treturn N - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tpublic static <T> boolean isEmpty(T[] array) {\n\t\treturn array == null || array.length == 0;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T getFirst(Object[] args, Class<?> clazz) {\n\t\tint index = indexOfFirst(args, clazz);\n\t\tif (index != -1) {\n\t\t\treturn (T) args[index];\n\t\t}\n\t\treturn null;\n\t}\n\n\n\tpublic static void checkOffsetAndCount(int arrayLength, int offset, int count) throws ArrayIndexOutOfBoundsException {\n\t\tif ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {\n\t\t\tthrow new ArrayIndexOutOfBoundsException(offset);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/AtomicFile.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * Static library support version of the framework's {@link android.util.AtomicFile},\n * a helper class for performing atomic operations on a file by creating a\n * backup file until a write has successfully completed.\n * <p>\n * Atomic file guarantees file integrity by ensuring that a file has\n * been completely written and sync'd to disk before removing its backup.\n * As long as the backup file exists, the original file is considered\n * to be invalid (left over from a previous attempt to write the file).\n * </p><p>\n * Atomic file does not confer any file locking semantics.\n * Do not use this class when the file may be accessed or modified concurrently\n * by multiple threads or processes.  The caller is responsible for ensuring\n * appropriate mutual exclusion invariants whenever it accesses the file.\n * </p>\n */\npublic class AtomicFile {\n    private final File mBaseName;\n    private final File mBackupName;\n\n    /**\n     * Create a new AtomicFile for a file located at the given File path.\n     * The secondary backup file will be the same file path with \".bak\" appended.\n     */\n    public AtomicFile(File baseName) {\n        mBaseName = baseName;\n        mBackupName = new File(baseName.getPath() + \".bak\");\n    }\n\n    /**\n     * Return the path to the base file.  You should not generally use this,\n     * as the data at that path may not be valid.\n     */\n    public File getBaseFile() {\n        return mBaseName;\n    }\n\n    /**\n     * Delete the atomic file.  This deletes both the base and backup files.\n     */\n    public void delete() {\n        mBaseName.delete();\n        mBackupName.delete();\n    }\n\n    /**\n     * Start a new write operation on the file.  This returns a FileOutputStream\n     * to which you can write the new file data.  The existing file is replaced\n     * with the new data.  You <em>must not</em> directly close the given\n     * FileOutputStream; instead call either {@link #finishWrite(FileOutputStream)}\n     * or {@link #failWrite(FileOutputStream)}.\n     * <p>\n     * <p>Note that if another thread is currently performing\n     * a write, this will simply replace whatever that thread is writing\n     * with the new file being written by this thread, and when the other\n     * thread finishes the write the new write operation will no longer be\n     * safe (or will be lost).  You must do your own threading protection for\n     * access to AtomicFile.\n     */\n    public FileOutputStream startWrite() throws IOException {\n        // Rename the current file so it may be used as a backup during the next read\n        if (mBaseName.exists()) {\n            if (!mBackupName.exists()) {\n                if (!mBaseName.renameTo(mBackupName)) {\n                    Log.w(\"AtomicFile\", \"Couldn't rename file \" + mBaseName\n                            + \" to backup file \" + mBackupName);\n                }\n            } else {\n                mBaseName.delete();\n            }\n        }\n        FileOutputStream str = null;\n        try {\n            str = new FileOutputStream(mBaseName);\n        } catch (FileNotFoundException e) {\n            File parent = mBaseName.getParentFile();\n            if (!parent.mkdir()) {\n                throw new IOException(\"Couldn't create directory \" + mBaseName);\n            }\n            try {\n                str = new FileOutputStream(mBaseName);\n            } catch (FileNotFoundException e2) {\n                throw new IOException(\"Couldn't create \" + mBaseName);\n            }\n        }\n        return str;\n    }\n\n    /**\n     * Call when you have successfully finished writing to the stream\n     * returned by {@link #startWrite()}.  This will close, sync, and\n     * commit the new data.  The next attempt to read the atomic file\n     * will return the new file stream.\n     */\n    public void finishWrite(FileOutputStream str) {\n        if (str != null) {\n            sync(str);\n            try {\n                str.close();\n                mBackupName.delete();\n            } catch (IOException e) {\n                Log.w(\"AtomicFile\", \"finishWrite: Got exception:\", e);\n            }\n        }\n    }\n\n    /**\n     * Call when you have failed for some reason at writing to the stream\n     * returned by {@link #startWrite()}.  This will close the current\n     * write stream, and roll back to the previous state of the file.\n     */\n    public void failWrite(FileOutputStream str) {\n        if (str != null) {\n            sync(str);\n            try {\n                str.close();\n                mBaseName.delete();\n                mBackupName.renameTo(mBaseName);\n            } catch (IOException e) {\n                Log.w(\"AtomicFile\", \"failWrite: Got exception:\", e);\n            }\n        }\n    }\n\n    /**\n     * Open the atomic file for reading.  If there previously was an\n     * incomplete write, this will roll back to the last good data before\n     * opening for read.  You should call close() on the FileInputStream when\n     * you are done reading from it.\n     * <p>\n     * <p>Note that if another thread is currently performing\n     * a write, this will incorrectly consider it to be in the state of a bad\n     * write and roll back, causing the new data currently being written to\n     * be dropped.  You must do your own threading protection for access to\n     * AtomicFile.\n     */\n    public FileInputStream openRead() throws FileNotFoundException {\n        if (mBackupName.exists()) {\n            mBaseName.delete();\n            mBackupName.renameTo(mBaseName);\n        }\n        return new FileInputStream(mBaseName);\n    }\n\n    /**\n     * A convenience for {@link #openRead()} that also reads all of the\n     * file contents into a byte array which is returned.\n     */\n    public byte[] readFully() throws IOException {\n        FileInputStream stream = openRead();\n        try {\n            int pos = 0;\n            int avail = stream.available();\n            byte[] data = new byte[avail];\n            while (true) {\n                int amt = stream.read(data, pos, data.length - pos);\n                //Log.i(\"foo\", \"Read \" + amt + \" bytes at \" + pos\n                //        + \" of avail \" + data.length);\n                if (amt <= 0) {\n                    //Log.i(\"foo\", \"**** FINISHED READING: pos=\" + pos\n                    //        + \" len=\" + data.length);\n                    return data;\n                }\n                pos += amt;\n                avail = stream.available();\n                if (avail > data.length - pos) {\n                    byte[] newData = new byte[pos + avail];\n                    System.arraycopy(data, 0, newData, 0, pos);\n                    data = newData;\n                }\n            }\n        } finally {\n            stream.close();\n        }\n    }\n\n    /**\n     * @deprecated This is not safe.\n     */\n    public void truncate() throws IOException {\n        try {\n            FileOutputStream fos = new FileOutputStream(mBaseName);\n            fos.getFD().sync();\n            fos.close();\n        } catch (FileNotFoundException e) {\n            throw new IOException(\"Couldn't append \" + mBaseName);\n        } catch (IOException e) {\n        }\n    }\n\n    /**\n     * @deprecated This is not safe.\n     */\n    @Deprecated public FileOutputStream openAppend() throws IOException {\n        try {\n            return new FileOutputStream(mBaseName, true);\n        } catch (FileNotFoundException e) {\n            throw new IOException(\"Couldn't append \" + mBaseName);\n        }\n    }\n\n    static boolean sync(FileOutputStream stream) {\n        try {\n            if (stream != null) {\n                stream.getFD().sync();\n            }\n            return true;\n        } catch (IOException e) {\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/BitmapUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\n\n/**\n * @author Lody\n */\npublic class BitmapUtils {\n\n    public static Bitmap drawableToBitmap(Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            BitmapDrawable bitmapDrawable = ((BitmapDrawable) drawable);\n            return bitmapDrawable.getBitmap();\n        } else {\n            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),\n                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);\n\n            Canvas canvas = new Canvas(bitmap);\n            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());\n            drawable.draw(canvas);\n            return bitmap;\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ClassUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\n/**\n * @author Lody\n *\n */\npublic class ClassUtils {\n\n\tpublic static boolean isClassExist(String className) {\n\t\ttry {\n\t\t\tClass.forName(className);\n\t\t\treturn true;\n\t\t} catch (ClassNotFoundException e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic static void fixArgs(Class<?>[] types, Object[] args) {\n\t\tfor (int i = 0; i < types.length; i++) {\n\t\t\tif (types[i] == int.class && args[i] == null) {\n\t\t\t\targs[i] = 0;\n\t\t\t} else if (types[i] == boolean.class && args[i] == null) {\n\t\t\t\targs[i] = false;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ComponentUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.os.IBinder;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.GmsSupport;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.SpecialComponentList;\nimport com.lody.virtual.client.ipc.VActivityManager;\nimport com.lody.virtual.client.stub.StubPendingActivity;\nimport com.lody.virtual.client.stub.StubPendingReceiver;\nimport com.lody.virtual.client.stub.StubPendingService;\nimport com.lody.virtual.helper.compat.ObjectsCompat;\nimport com.lody.virtual.os.VUserHandle;\n\nimport static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;\n\n/**\n * @author Lody\n */\npublic class ComponentUtils {\n\n    public static String getTaskAffinity(ActivityInfo info) {\n        if (info.launchMode == LAUNCH_SINGLE_INSTANCE) {\n            return \"-SingleInstance-\" + info.packageName + \"/\" + info.name;\n        } else if (info.taskAffinity == null && info.applicationInfo.taskAffinity == null) {\n            return info.packageName;\n        } else if (info.taskAffinity != null) {\n            return info.taskAffinity;\n        }\n        return info.applicationInfo.taskAffinity;\n    }\n\n    public static boolean isSameIntent(Intent a, Intent b) {\n        if (a != null && b != null) {\n            if (!ObjectsCompat.equals(a.getAction(), b.getAction())) {\n                return false;\n            }\n            if (!ObjectsCompat.equals(a.getData(), b.getData())) {\n                return false;\n            }\n            if (!ObjectsCompat.equals(a.getType(), b.getType())) {\n                return false;\n            }\n            Object pkgA = a.getPackage();\n            if (pkgA == null && a.getComponent() != null) {\n                pkgA = a.getComponent().getPackageName();\n            }\n            String pkgB = b.getPackage();\n            if (pkgB == null && b.getComponent() != null) {\n                pkgB = b.getComponent().getPackageName();\n            }\n            if (!ObjectsCompat.equals(pkgA, pkgB)) {\n                return false;\n            }\n            if (!ObjectsCompat.equals(a.getComponent(), b.getComponent())) {\n                return false;\n            }\n            if (!ObjectsCompat.equals(a.getCategories(), b.getCategories())) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static String getProcessName(ComponentInfo componentInfo) {\n        String processName = componentInfo.processName;\n        if (processName == null) {\n            processName = componentInfo.packageName;\n            componentInfo.processName = processName;\n        }\n        return processName;\n    }\n\n    public static boolean isSameComponent(ComponentInfo first, ComponentInfo second) {\n\n        if (first != null && second != null) {\n            String pkg1 = first.packageName + \"\";\n            String pkg2 = second.packageName + \"\";\n            String name1 = first.name + \"\";\n            String name2 = second.name + \"\";\n            return pkg1.equals(pkg2) && name1.equals(name2);\n        }\n        return false;\n    }\n\n    public static ComponentName toComponentName(ComponentInfo componentInfo) {\n        return new ComponentName(componentInfo.packageName, componentInfo.name);\n    }\n\n    public static boolean isSystemApp(ApplicationInfo applicationInfo) {\n        return !GmsSupport.isGmsFamilyPackage(applicationInfo.packageName)\n                && ((ApplicationInfo.FLAG_SYSTEM & applicationInfo.flags) != 0\n                || SpecialComponentList.SpecSystemComponent.isSpecSystemPackage(applicationInfo.packageName));\n    }\n\n    public static boolean isStubComponent(Intent intent) {\n        return intent != null\n                && intent.getComponent() != null\n                && VirtualCore.get().getHostPkg().equals(intent.getComponent().getPackageName());\n    }\n\n    public static Intent redirectBroadcastIntent(Intent intent, int userId) {\n        Intent newIntent = intent.cloneFilter();\n        newIntent.setComponent(null);\n        newIntent.setPackage(null);\n        ComponentName component = intent.getComponent();\n        String pkg = intent.getPackage();\n        if (component != null) {\n            newIntent.putExtra(\"_VA_|_user_id_\", userId);\n            newIntent.setAction(String.format(\"_VA_%s_%s\", component.getPackageName(), component.getClassName()));\n            newIntent.putExtra(\"_VA_|_component_\", component);\n            newIntent.putExtra(\"_VA_|_intent_\", new Intent(intent));\n        } else if (pkg != null) {\n            newIntent.putExtra(\"_VA_|_user_id_\", userId);\n            newIntent.putExtra(\"_VA_|_creator_\", pkg);\n            newIntent.putExtra(\"_VA_|_intent_\", new Intent(intent));\n            String protectedAction = SpecialComponentList.protectAction(intent.getAction());\n            if (protectedAction != null) {\n                newIntent.setAction(protectedAction);\n            }\n        } else {\n            newIntent.putExtra(\"_VA_|_user_id_\", userId);\n            newIntent.putExtra(\"_VA_|_intent_\", new Intent(intent));\n            String protectedAction = SpecialComponentList.protectAction(intent.getAction());\n            if (protectedAction != null) {\n                newIntent.setAction(protectedAction);\n            }\n        }\n        return newIntent;\n    }\n\n    public static Intent redirectIntentSender(int type, String creator, Intent intent, IBinder iBinder) {\n        Intent cloneFilter = intent.cloneFilter();\n        switch (type) {\n            case 1:\n                cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingReceiver.class);\n                break;\n            case 2:\n                if (VirtualCore.get().resolveActivityInfo(intent, VUserHandle.myUserId()) != null) {\n                    cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingActivity.class);\n                    cloneFilter.setFlags(intent.getFlags());\n                    if (iBinder != null) {\n                        try {\n                            Parcelable activityForToken = VActivityManager.get().getActivityForToken(iBinder);\n                            if (activityForToken != null) {\n                                cloneFilter.putExtra(\"_VA_|_caller_\", activityForToken);\n                                break;\n                            }\n                        } catch (Throwable th) {\n                            break;\n                        }\n                    }\n                }\n                break;\n            case 4:\n                if (VirtualCore.get().resolveServiceInfo(intent, VUserHandle.myUserId()) != null) {\n                    cloneFilter.setClass(VirtualCore.get().getContext(), StubPendingService.class);\n                    break;\n                }\n                break;\n            default:\n                return null;\n        }\n        cloneFilter.putExtra(\"_VA_|_user_id_\", VUserHandle.myUserId());\n        cloneFilter.putExtra(\"_VA_|_intent_\", intent);\n        cloneFilter.putExtra(\"_VA_|_creator_\", creator);\n        cloneFilter.putExtra(\"_VA_|_from_inner_\", true);\n        return cloneFilter;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/DeviceUtil.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.os.Build;\n\n/**\n * author: weishu on 18/1/17.\n */\n\npublic class DeviceUtil {\n    /**\n     * is Meizu Android L/M device\n     * @return\n     */\n    public static boolean isMeizuBelowN() {\n        if (Build.VERSION.SDK_INT > 23) {\n            return false;\n        }\n        String display = Build.DISPLAY;\n        return display.toLowerCase().contains(\"flyme\");\n    }\n\n    public static boolean isSamsung() {\n        return \"samsung\".equalsIgnoreCase(Build.BRAND) || \"samsung\".equalsIgnoreCase(Build.MANUFACTURER);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/DrawableUtils.java",
    "content": "package com.lody.virtual.helper.utils;\r\n\r\nimport android.graphics.Bitmap;\r\nimport android.graphics.Canvas;\r\nimport android.graphics.PixelFormat;\r\nimport android.graphics.drawable.BitmapDrawable;\r\nimport android.graphics.drawable.Drawable;\r\n\r\npublic class DrawableUtils {\r\n    public static Bitmap drawableToBitMap(Drawable drawable) {\r\n        if (drawable == null) {\r\n            return null;\r\n        }\r\n        if (drawable instanceof BitmapDrawable) {\r\n            BitmapDrawable bitmapDrawable = ((BitmapDrawable) drawable);\r\n            return bitmapDrawable.getBitmap();\r\n        } else {\r\n            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),\r\n                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);\r\n            Canvas canvas = new Canvas(bitmap);\r\n            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());\r\n            drawable.draw(canvas);\r\n            return bitmap;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/EncodeUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.util.Base64;\n\n/**\n * @author weishu\n * @date 18/3/20.\n */\npublic class EncodeUtils {\n\n    public static String decode(String base64) {\n        return new String(Base64.decode(base64, 0));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/FastXmlSerializer.java",
    "content": "/*\n * Copyright (C) 2006 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.helper.utils;\n\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.io.Writer;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetEncoder;\nimport java.nio.charset.CoderResult;\nimport java.nio.charset.IllegalCharsetNameException;\nimport java.nio.charset.UnsupportedCharsetException;\n\n/**\n * This is a quick and dirty implementation of XmlSerializer that isn't horribly\n * painfully slow like the normal one.  It only does what is needed for the\n * specific XML files being written with it.\n */\npublic class FastXmlSerializer implements XmlSerializer {\n    private static final String ESCAPE_TABLE[] = new String[] {\n        null,     null,     null,     null,     null,     null,     null,     null,  // 0-7\n        null,     null,     null,     null,     null,     null,     null,     null,  // 8-15\n        null,     null,     null,     null,     null,     null,     null,     null,  // 16-23\n        null,     null,     null,     null,     null,     null,     null,     null,  // 24-31\n        null,     null,     \"&quot;\", null,     null,     null,     \"&amp;\",  null,  // 32-39\n        null,     null,     null,     null,     null,     null,     null,     null,  // 40-47\n        null,     null,     null,     null,     null,     null,     null,     null,  // 48-55\n        null,     null,     null,     null,     \"&lt;\",   null,     \"&gt;\",   null,  // 56-63\n    };\n\n    private static final int BUFFER_LEN = 8192;\n\n    private static String sSpace = \"                                                              \";\n\n    private final char[] mText = new char[BUFFER_LEN];\n    private int mPos;\n\n    private Writer mWriter;\n\n    private OutputStream mOutputStream;\n    private CharsetEncoder mCharset;\n    private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);\n\n    private boolean mIndent = false;\n    private boolean mInTag;\n\n    private int mNesting = 0;\n    private boolean mLineStart = true;\n\n    private void append(char c) throws IOException {\n        int pos = mPos;\n        if (pos >= (BUFFER_LEN-1)) {\n            flush();\n            pos = mPos;\n        }\n        mText[pos] = c;\n        mPos = pos+1;\n    }\n\n    private void append(String str, int i, final int length) throws IOException {\n        if (length > BUFFER_LEN) {\n            final int end = i + length;\n            while (i < end) {\n                int next = i + BUFFER_LEN;\n                append(str, i, next<end ? BUFFER_LEN : (end-i));\n                i = next;\n            }\n            return;\n        }\n        int pos = mPos;\n        if ((pos+length) > BUFFER_LEN) {\n            flush();\n            pos = mPos;\n        }\n        str.getChars(i, i+length, mText, pos);\n        mPos = pos + length;\n    }\n\n    private void append(char[] buf, int i, final int length) throws IOException {\n        if (length > BUFFER_LEN) {\n            final int end = i + length;\n            while (i < end) {\n                int next = i + BUFFER_LEN;\n                append(buf, i, next<end ? BUFFER_LEN : (end-i));\n                i = next;\n            }\n            return;\n        }\n        int pos = mPos;\n        if ((pos+length) > BUFFER_LEN) {\n            flush();\n            pos = mPos;\n        }\n        System.arraycopy(buf, i, mText, pos, length);\n        mPos = pos + length;\n    }\n\n    private void append(String str) throws IOException {\n        append(str, 0, str.length());\n    }\n\n    private void appendIndent(int indent) throws IOException {\n        indent *= 4;\n        if (indent > sSpace.length()) {\n            indent = sSpace.length();\n        }\n        append(sSpace, 0, indent);\n    }\n\n    private void escapeAndAppendString(final String string) throws IOException {\n        final int N = string.length();\n        final char NE = (char)ESCAPE_TABLE.length;\n        final String[] escapes = ESCAPE_TABLE;\n        int lastPos = 0;\n        int pos;\n        for (pos=0; pos<N; pos++) {\n            char c = string.charAt(pos);\n            if (c >= NE) continue;\n            String escape = escapes[c];\n            if (escape == null) continue;\n            if (lastPos < pos) append(string, lastPos, pos-lastPos);\n            lastPos = pos + 1;\n            append(escape);\n        }\n        if (lastPos < pos) append(string, lastPos, pos-lastPos);\n    }\n\n    private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {\n        final char NE = (char)ESCAPE_TABLE.length;\n        final String[] escapes = ESCAPE_TABLE;\n        int end = start+len;\n        int lastPos = start;\n        int pos;\n        for (pos=start; pos<end; pos++) {\n            char c = buf[pos];\n            if (c >= NE) continue;\n            String escape = escapes[c];\n            if (escape == null) continue;\n            if (lastPos < pos) append(buf, lastPos, pos-lastPos);\n            lastPos = pos + 1;\n            append(escape);\n        }\n        if (lastPos < pos) append(buf, lastPos, pos-lastPos);\n    }\n\n    public XmlSerializer attribute(String namespace, String name, String value) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        append(' ');\n        if (namespace != null) {\n            append(namespace);\n            append(':');\n        }\n        append(name);\n        append(\"=\\\"\");\n\n        escapeAndAppendString(value);\n        append('\"');\n        mLineStart = false;\n        return this;\n    }\n\n    public void cdsect(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void comment(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void docdecl(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {\n        flush();\n    }\n\n    public XmlSerializer endTag(String namespace, String name) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        mNesting--;\n        if (mInTag) {\n            append(\" />\\n\");\n        } else {\n            if (mIndent && mLineStart) {\n                appendIndent(mNesting);\n            }\n            append(\"</\");\n            if (namespace != null) {\n                append(namespace);\n                append(':');\n            }\n            append(name);\n            append(\">\\n\");\n        }\n        mLineStart = true;\n        mInTag = false;\n        return this;\n    }\n\n    public void entityRef(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    private void flushBytes() throws IOException {\n        int position;\n        if ((position = mBytes.position()) > 0) {\n            mBytes.flip();\n            mOutputStream.write(mBytes.array(), 0, position);\n            mBytes.clear();\n        }\n    }\n\n    public void flush() throws IOException {\n        //Log.i(\"PackageManager\", \"flush mPos=\" + mPos);\n        if (mPos > 0) {\n            if (mOutputStream != null) {\n                CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);\n                CoderResult result = mCharset.encode(charBuffer, mBytes, true);\n                while (true) {\n                    if (result.isError()) {\n                        throw new IOException(result.toString());\n                    } else if (result.isOverflow()) {\n                        flushBytes();\n                        result = mCharset.encode(charBuffer, mBytes, true);\n                        continue;\n                    }\n                    break;\n                }\n                flushBytes();\n                mOutputStream.flush();\n            } else {\n                mWriter.write(mText, 0, mPos);\n                mWriter.flush();\n            }\n            mPos = 0;\n        }\n    }\n\n    public int getDepth() {\n        throw new UnsupportedOperationException();\n    }\n\n    public boolean getFeature(String name) {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getName() {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getNamespace() {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getPrefix(String namespace, boolean generatePrefix)\n            throws IllegalArgumentException {\n        throw new UnsupportedOperationException();\n    }\n\n    public Object getProperty(String name) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void processingInstruction(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setFeature(String name, boolean state) throws IllegalArgumentException,\n            IllegalStateException {\n        if (name.equals(\"http://xmlpull.org/v1/doc/features.html#indent-output\")) {\n            mIndent = true;\n            return;\n        }\n        throw new UnsupportedOperationException();\n    }\n\n    public void setOutput(OutputStream os, String encoding) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (os == null)\n            throw new IllegalArgumentException();\n        try {\n            mCharset = Charset.forName(encoding).newEncoder();\n        } catch (IllegalCharsetNameException e) {\n            throw (UnsupportedEncodingException) (new UnsupportedEncodingException(\n                    encoding).initCause(e));\n        } catch (UnsupportedCharsetException e) {\n            throw (UnsupportedEncodingException) (new UnsupportedEncodingException(\n                    encoding).initCause(e));\n        }\n        mOutputStream = os;\n    }\n\n    public void setOutput(Writer writer) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        mWriter = writer;\n    }\n\n    public void setPrefix(String prefix, String namespace) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setProperty(String name, Object value) throws IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void startDocument(String encoding, Boolean standalone) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        append(\"<?xml version='1.0' encoding='utf-8' standalone='\"\n                + (standalone ? \"yes\" : \"no\") + \"' ?>\\n\");\n        mLineStart = true;\n    }\n\n    public XmlSerializer startTag(String namespace, String name) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (mInTag) {\n            append(\">\\n\");\n        }\n        if (mIndent) {\n            appendIndent(mNesting);\n        }\n        mNesting++;\n        append('<');\n        if (namespace != null) {\n            append(namespace);\n            append(':');\n        }\n        append(name);\n        mInTag = true;\n        mLineStart = false;\n        return this;\n    }\n\n    public XmlSerializer text(char[] buf, int start, int len) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (mInTag) {\n            append(\">\");\n            mInTag = false;\n        }\n        escapeAndAppendString(buf, start, len);\n        if (mIndent) {\n            mLineStart = buf[start+len-1] == '\\n';\n        }\n        return this;\n    }\n\n    public XmlSerializer text(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        if (mInTag) {\n            append(\">\");\n            mInTag = false;\n        }\n        escapeAndAppendString(text);\n        if (mIndent) {\n            mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\\n');\n        }\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/FileUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.system.Os;\nimport android.text.TextUtils;\n\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.Channels;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.ReadableByteChannel;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * @author Lody\n */\npublic class FileUtils {\n    /**\n     * @param path\n     * @param mode {@link FileMode}\n     * @throws Exception\n     */\n    public static void chmod(String path, int mode) throws Exception {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            try {\n                Os.chmod(path, mode);\n                return;\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n\n        File file = new File(path);\n        String cmd = \"chmod \";\n        if (file.isDirectory()) {\n            cmd += \" -R \";\n        }\n        String cmode = String.format(\"%o\", mode);\n        Runtime.getRuntime().exec(cmd + cmode + \" \" + path).waitFor();\n    }\n\n    public static void createSymlink(String oldPath, String newPath) throws Exception {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            Os.symlink(oldPath, newPath);\n        } else {\n            Runtime.getRuntime().exec(\"ln -s \" + oldPath + \" \" + newPath).waitFor();\n        }\n    }\n\n    public static boolean isSymlink(File file) throws IOException {\n        if (file == null)\n            throw new NullPointerException(\"File must not be null\");\n        File canon;\n        if (file.getParent() == null) {\n            canon = file;\n        } else {\n            File canonDir = file.getParentFile().getCanonicalFile();\n            canon = new File(canonDir, file.getName());\n        }\n        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());\n    }\n\n    public static void writeParcelToFile(Parcel p, File file) throws IOException {\n        FileOutputStream fos = new FileOutputStream(file);\n        fos.write(p.marshall());\n        fos.close();\n    }\n\n    public static byte[] toByteArray(InputStream inStream) throws IOException {\n        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();\n        byte[] buff = new byte[100];\n        int rc;\n        while ((rc = inStream.read(buff, 0, 100)) > 0) {\n            swapStream.write(buff, 0, rc);\n        }\n        return swapStream.toByteArray();\n    }\n\n    public static boolean deleteDir(File dir) {\n        if (dir == null) {\n            return false;\n        }\n        boolean success = true;\n        if (dir.isDirectory()) {\n            String[] children = dir.list();\n            for (String file : children) {\n                boolean ret = deleteDir(new File(dir, file));\n                if (!ret) {\n                    success = false;\n                }\n            }\n            if (success) {\n                // if all subdirectory are deleted, delete the dir itself.\n                return dir.delete();\n            }\n        }\n        return dir.delete();\n    }\n\n    public static boolean deleteDir(File dir, Set<File> ignores) {\n        if (dir.isDirectory()) {\n            String[] children = dir.list();\n            for (String file : children) {\n                boolean success = deleteDir(new File(dir, file), ignores);\n                if (!success) {\n                    return false;\n                }\n            }\n        }\n        return ignores != null && ignores.contains(dir) || dir.delete();\n    }\n\n    public static boolean deleteDir(String dir) {\n        return deleteDir(new File(dir));\n    }\n\n    public static void writeToFile(InputStream dataIns, File target) throws IOException {\n        final int BUFFER = 1024;\n        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target));\n        int count;\n        byte data[] = new byte[BUFFER];\n        while ((count = dataIns.read(data, 0, BUFFER)) != -1) {\n            bos.write(data, 0, count);\n        }\n        bos.close();\n    }\n\n    public static String getFileFromUri(Context context, Uri packageUri) {\n\n        if (packageUri == null) {\n            return null;\n        }\n\n        final String SCHEME_FILE = \"file\";\n        final String SCHEME_CONTENT = \"content\";\n        String sourcePath = null;\n\n        if (SCHEME_FILE.equals(packageUri.getScheme())) {\n            sourcePath = packageUri.getPath();\n        } else if (SCHEME_CONTENT.equals(packageUri.getScheme())){\n            InputStream inputStream = null;\n            OutputStream outputStream = null;\n            File sharedFileCopy = new File(context.getCacheDir(), packageUri.getLastPathSegment());\n            try {\n                inputStream = context.getContentResolver().openInputStream(packageUri);\n                outputStream = new FileOutputStream(sharedFileCopy);\n                byte[] buffer = new byte[1024];\n                int count;\n                while ((count = inputStream.read(buffer)) > 0) {\n                    outputStream.write(buffer, 0, count);\n                }\n                outputStream.flush();\n\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                FileUtils.closeQuietly(inputStream);\n                FileUtils.closeQuietly(outputStream);\n            }\n            sourcePath = sharedFileCopy.getPath();\n        }\n        return sourcePath;\n    }\n\n    public static void writeToFile(byte[] data, File target) throws IOException {\n        FileOutputStream fo = null;\n        ReadableByteChannel src = null;\n        FileChannel out = null;\n        try {\n            src = Channels.newChannel(new ByteArrayInputStream(data));\n            fo = new FileOutputStream(target);\n            out = fo.getChannel();\n            out.transferFrom(src, 0, data.length);\n        } finally {\n            if (fo != null) {\n                fo.close();\n            }\n            if (src != null) {\n                src.close();\n            }\n            if (out != null) {\n                out.close();\n            }\n        }\n    }\n\n    public static void copyFile(File source, File target) throws IOException {\n\n        FileInputStream inputStream = null;\n        FileOutputStream outputStream = null;\n        try {\n            inputStream = new FileInputStream(source);\n            outputStream = new FileOutputStream(target);\n            FileChannel iChannel = inputStream.getChannel();\n            FileChannel oChannel = outputStream.getChannel();\n\n            ByteBuffer buffer = ByteBuffer.allocate(1024);\n            while (true) {\n                buffer.clear();\n                int r = iChannel.read(buffer);\n                if (r == -1)\n                    break;\n                buffer.limit(buffer.position());\n                buffer.position(0);\n                oChannel.write(buffer);\n            }\n        } finally {\n            closeQuietly(inputStream);\n            closeQuietly(outputStream);\n        }\n    }\n\n    public static void copyFile(String source, String target) throws IOException {\n        File from = new File(source);\n        if (!from.exists()) {\n            return;\n        }\n        if (from.isFile()) {\n            copyFile(from, new File(target));\n        } else {\n            copyDir(source, target);\n        }\n    }\n\n    public static void copyDir(String sourcePath, String targetPath) throws IOException {\n        File from = new File(sourcePath);\n        if (!from.exists()) {\n            return;\n        }\n\n        File to = new File(targetPath);\n        if (!to.exists()) {\n            boolean mkdirs = to.mkdirs();\n            if (!mkdirs) {\n                return;\n            }\n        }\n\n        String[] child = from.list();\n        for (String file : child) {\n            File childSource = new File(sourcePath, file);\n            if (childSource.isDirectory()) {\n                copyDir(sourcePath + File.separator + file, targetPath + File.separator + file);\n            } else {\n                copyFile(childSource, new File(targetPath, file));\n            }\n        }\n    }\n\n    public static void closeQuietly(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    public static int peekInt(byte[] bytes, int value, ByteOrder endian) {\n        int v2;\n        int v0;\n        if (endian == ByteOrder.BIG_ENDIAN) {\n            v0 = value + 1;\n            v2 = v0 + 1;\n            v0 = (bytes[v0] & 255) << 16 | (bytes[value] & 255) << 24 | (bytes[v2] & 255) << 8 | bytes[v2 + 1] & 255;\n        } else {\n            v0 = value + 1;\n            v2 = v0 + 1;\n            v0 = (bytes[v0] & 255) << 8 | bytes[value] & 255 | (bytes[v2] & 255) << 16 | (bytes[v2 + 1] & 255) << 24;\n        }\n\n        return v0;\n    }\n\n    private static boolean isValidExtFilenameChar(char c) {\n        switch (c) {\n            case '\\0':\n            case '/':\n                return false;\n            default:\n                return true;\n        }\n    }\n\n    /**\n     * Check if given filename is valid for an ext4 filesystem.\n     */\n    public static boolean isValidExtFilename(String name) {\n        return (name != null) && name.equals(buildValidExtFilename(name));\n    }\n\n    /**\n     * Mutate the given filename to make it valid for an ext4 filesystem,\n     * replacing any invalid characters with \"_\".\n     */\n    public static String buildValidExtFilename(String name) {\n        if (TextUtils.isEmpty(name) || \".\".equals(name) || \"..\".equals(name)) {\n            return \"(invalid)\";\n        }\n        final StringBuilder res = new StringBuilder(name.length());\n        for (int i = 0; i < name.length(); i++) {\n            final char c = name.charAt(i);\n            if (isValidExtFilenameChar(c)) {\n                res.append(c);\n            } else {\n                res.append('_');\n            }\n        }\n        return res.toString();\n    }\n\n    public interface FileMode {\n        int MODE_ISUID = 04000;\n        int MODE_ISGID = 02000;\n        int MODE_ISVTX = 01000;\n        int MODE_IRUSR = 00400;\n        int MODE_IWUSR = 00200;\n        int MODE_IXUSR = 00100;\n        int MODE_IRGRP = 00040;\n        int MODE_IWGRP = 00020;\n        int MODE_IXGRP = 00010;\n        int MODE_IROTH = 00004;\n        int MODE_IWOTH = 00002;\n        int MODE_IXOTH = 00001;\n\n        int MODE_755 = MODE_IRUSR | MODE_IWUSR | MODE_IXUSR\n                | MODE_IRGRP | MODE_IXGRP\n                | MODE_IROTH | MODE_IXOTH;\n    }\n\n    /**\n     * Lock the specified fle\n     */\n    public static class FileLock {\n        private static FileLock singleton;\n        private Map<String, FileLockCount> mRefCountMap = new ConcurrentHashMap<String, FileLockCount>();\n\n        public static FileLock getInstance() {\n            if (singleton == null) {\n                singleton = new FileLock();\n            }\n            return singleton;\n        }\n\n        private int RefCntInc(String filePath, java.nio.channels.FileLock fileLock, RandomAccessFile randomAccessFile,\n                              FileChannel fileChannel) {\n            int refCount;\n            if (this.mRefCountMap.containsKey(filePath)) {\n                FileLockCount fileLockCount = this.mRefCountMap.get(filePath);\n                int i = fileLockCount.mRefCount;\n                fileLockCount.mRefCount = i + 1;\n                refCount = i;\n            } else {\n                refCount = 1;\n                this.mRefCountMap.put(filePath, new FileLockCount(fileLock, refCount, randomAccessFile, fileChannel));\n\n            }\n            return refCount;\n        }\n\n        private int RefCntDec(String filePath) {\n            int refCount = 0;\n            if (this.mRefCountMap.containsKey(filePath)) {\n                FileLockCount fileLockCount = this.mRefCountMap.get(filePath);\n                int i = fileLockCount.mRefCount - 1;\n                fileLockCount.mRefCount = i;\n                refCount = i;\n                if (refCount <= 0) {\n                    this.mRefCountMap.remove(filePath);\n                }\n            }\n            return refCount;\n        }\n\n        public boolean LockExclusive(File targetFile) {\n\n            if (targetFile == null) {\n                return false;\n            }\n            try {\n                File lockFile = new File(targetFile.getParentFile().getAbsolutePath().concat(\"/lock\"));\n                if (!lockFile.exists()) {\n                    lockFile.createNewFile();\n                }\n                RandomAccessFile randomAccessFile = new RandomAccessFile(lockFile.getAbsolutePath(), \"rw\");\n                FileChannel channel = randomAccessFile.getChannel();\n                java.nio.channels.FileLock lock = channel.lock();\n                if (!lock.isValid()) {\n                    return false;\n                }\n                RefCntInc(lockFile.getAbsolutePath(), lock, randomAccessFile, channel);\n                return true;\n            } catch (Exception e) {\n                return false;\n            }\n        }\n\n        /**\n         * unlock odex file\n         **/\n        public void unLock(File targetFile) {\n\n            File lockFile = new File(targetFile.getParentFile().getAbsolutePath().concat(\"/lock\"));\n            if (!lockFile.exists()) {\n                return;\n            }\n            if (this.mRefCountMap.containsKey(lockFile.getAbsolutePath())) {\n                FileLockCount fileLockCount = this.mRefCountMap.get(lockFile.getAbsolutePath());\n                if (fileLockCount != null) {\n                    java.nio.channels.FileLock fileLock = fileLockCount.mFileLock;\n                    RandomAccessFile randomAccessFile = fileLockCount.fOs;\n                    FileChannel fileChannel = fileLockCount.fChannel;\n                    try {\n                        if (RefCntDec(lockFile.getAbsolutePath()) <= 0) {\n                            if (fileLock != null && fileLock.isValid()) {\n                                fileLock.release();\n                            }\n                            if (randomAccessFile != null) {\n                                randomAccessFile.close();\n                            }\n                            if (fileChannel != null) {\n                                fileChannel.close();\n                            }\n                        }\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }\n\n        private class FileLockCount {\n            FileChannel fChannel;\n            RandomAccessFile fOs;\n            java.nio.channels.FileLock mFileLock;\n            int mRefCount;\n\n            FileLockCount(java.nio.channels.FileLock fileLock, int mRefCount, RandomAccessFile fOs,\n                          FileChannel fChannel) {\n                this.mFileLock = fileLock;\n                this.mRefCount = mRefCount;\n                this.fOs = fOs;\n                this.fChannel = fChannel;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/MD5Utils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\nimport android.text.TextUtils;\n\n/**\n * @author Lody\n *\n *\n */\npublic class MD5Utils {\n\n\t/**\n\t * 默认的密码字符串组合，用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合\n\t */\n\tprotected static char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',\n\t\t\t'f'};\n\tprotected static MessageDigest MESSAGE_DIGEST_5 = null;\n\n\tstatic {\n\t\ttry {\n\t\t\tMESSAGE_DIGEST_5 = MessageDigest.getInstance(\"MD5\");\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\tpublic static String getFileMD5String(File file) throws IOException {\n\t\tInputStream fis;\n\t\tfis = new FileInputStream(file);\n\t\tbyte[] buffer = new byte[1024];\n\t\tint numRead;\n\t\twhile ((numRead = fis.read(buffer)) > 0) {\n\t\t\tMESSAGE_DIGEST_5.update(buffer, 0, numRead);\n\t\t}\n\t\tfis.close();\n\t\treturn bufferToHex(MESSAGE_DIGEST_5.digest());\n\t}\n\n\tpublic static String getFileMD5String(InputStream in) throws IOException {\n\t\tbyte[] buffer = new byte[1024];\n\t\tint numRead;\n\t\twhile ((numRead = in.read(buffer)) > 0) {\n\t\t\tMESSAGE_DIGEST_5.update(buffer, 0, numRead);\n\t\t}\n\t\tin.close();\n\t\treturn bufferToHex(MESSAGE_DIGEST_5.digest());\n\t}\n\tprivate static String bufferToHex(byte bytes[]) {\n\t\treturn bufferToHex(bytes, 0, bytes.length);\n\t}\n\tprivate static String bufferToHex(byte bytes[], int m, int n) {\n\t\tStringBuffer stringbuffer = new StringBuffer(2 * n);\n\t\tint k = m + n;\n\t\tfor (int l = m; l < k; l++) {\n\t\t\tappendHexPair(bytes[l], stringbuffer);\n\t\t}\n\t\treturn stringbuffer.toString();\n\t}\n\tprivate static void appendHexPair(byte bt, StringBuffer stringbuffer) {\n\t\tchar c0 = HEX_DIGITS[(bt & 0xf0) >> 4];\n\t\tchar c1 = HEX_DIGITS[bt & 0xf];\n\t\tstringbuffer.append(c0);\n\t\tstringbuffer.append(c1);\n\t}\n\n\tpublic static boolean compareFiles(File one, File two) throws IOException {\n\n\t\tif (one.getAbsolutePath().equals(two.getAbsolutePath())) {\n\t\t\t// 是同一个文件\n\t\t\treturn true;\n\t\t}\n\t\tString md5_1 = getFileMD5String(one);\n\t\tString md5_2 = getFileMD5String(two);\n\t\treturn TextUtils.equals(md5_1, md5_2);\n\t}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/OSUtils.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.Properties;\n\nimport android.os.Build;\nimport android.os.Environment;\nimport android.text.TextUtils;\n\n/**\n * Created by 247321453 on 2016/7/17.\n */\npublic class OSUtils {\n\tprivate static final String KEY_EMUI_VERSION_CODE = \"ro.build.version.emui\";\n\tprivate static final String KEY_MIUI_VERSION_CODE = \"ro.miui.ui.version.code\";\n\tprivate static final String KEY_MIUI_VERSION_NAME = \"ro.miui.ui.version.name\";\n\tprivate static final String KEY_MIUI_INTERNAL_STORAGE = \"ro.miui.internal.storage\";\n\n\tprivate static final OSUtils sOSUtils = new OSUtils();\n\tprivate boolean emui;\n\tprivate boolean miui;\n\tprivate boolean flyme;\n\tprivate String miuiVersion;\n\tprivate OSUtils() {\n\t\tProperties properties;\n\t\ttry {\n\t\t\tproperties = new Properties();\n\t\t\tproperties.load(new FileInputStream(new File(Environment.getRootDirectory(), \"build.prop\")));\n\t\t} catch (IOException e) {\n\t\t\tproperties = null;\n\t\t}\n\t\tif (properties != null) {\n\t\t\temui = !TextUtils.isEmpty(properties.getProperty(KEY_EMUI_VERSION_CODE));\n\t\t\tmiuiVersion = properties.getProperty(KEY_MIUI_VERSION_CODE);\n\t\t\tmiui = !TextUtils.isEmpty(miuiVersion) || !TextUtils.isEmpty(properties.getProperty(KEY_MIUI_VERSION_NAME))\n\t\t\t\t\t|| !TextUtils.isEmpty(properties.getProperty(KEY_MIUI_INTERNAL_STORAGE));\n\t\t}\n\t\tflyme = hasFlyme();\n\t}\n\n\tpublic static OSUtils getInstance() {\n\t\treturn sOSUtils;\n\t}\n\n\tpublic String getMiuiVersion() {\n\t\treturn miuiVersion;\n\t}\n\n\tpublic boolean isEmui() {\n\t\treturn emui;\n\t}\n\n\tpublic boolean isMiui() {\n\t\treturn miui;\n\t}\n\n\tpublic boolean isFlyme() {\n\t\treturn flyme;\n\t}\n\n\tprivate boolean hasFlyme() {\n\t\ttry {\n\t\t\tfinal Method method = Build.class.getMethod(\"hasSmartBar\");\n\t\t\treturn method != null;\n\t\t} catch (final Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/Reflect.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport java.lang.reflect.AccessibleObject;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.Proxy;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * 一个拥有流畅特性(Fluent-API)的反射工具类, 使用起来就像直接调用一样流畅易懂.\n *\n * @author Lody\n */\npublic class Reflect {\n\n    private final Object object;\n    private final boolean isClass;\n\n    private Reflect(Class<?> type) {\n        this.object = type;\n        this.isClass = true;\n    }\n\n    private Reflect(Object object) {\n        this.object = object;\n        this.isClass = false;\n    }\n\n    /**\n     * 根据指定的类名构建反射工具类\n     *\n     * @param name 类的全名\n     * @return 反射工具类\n     * @throws ReflectException 如果反射出现意外\n     * @see #on(Class)\n     */\n    public static Reflect on(String name) throws ReflectException {\n        return on(forName(name));\n    }\n\n    /**\n     * 从指定的类加载起寻找类,并构建反射工具类\n     *\n     * @param name        类的全名\n     * @param classLoader 需要构建工具类的类的类加载器 loaded.\n     * @return 反射工具类\n     * @throws ReflectException 如果反射出现意外\n     * @see #on(Class)\n     */\n    public static Reflect on(String name, ClassLoader classLoader) throws ReflectException {\n        return on(forName(name, classLoader));\n    }\n\n    /**\n     * 根据指定的类构建反射工具类\n     * <p>\n     * 当你需要访问静态字段的时候本方法适合你, 你还可以通过调用 {@link #create(Object...)} 创建一个对象.\n     *\n     * @param clazz 需要构建反射工具类的类\n     * @return 反射工具类\n     */\n    public static Reflect on(Class<?> clazz) {\n        return new Reflect(clazz);\n    }\n\n    // ---------------------------------------------------------------------\n    // 构造器\n    // ---------------------------------------------------------------------\n\n    /**\n     * Wrap an object.\n     * <p>\n     * Use this when you want to access instance fields and methods on any\n     * {@link Object}\n     *\n     * @param object The object to be wrapped\n     * @return A wrapped object, to be used for further reflection.\n     */\n    public static Reflect on(Object object) {\n        return new Reflect(object);\n    }\n\n    /**\n     * 让一个{@link AccessibleObject}可访问.\n     *\n     * @param accessible\n     * @param <T>\n     * @return\n     */\n    public static <T extends AccessibleObject> T accessible(T accessible) {\n        if (accessible == null) {\n            return null;\n        }\n\n        if (accessible instanceof Member) {\n            Member member = (Member) accessible;\n\n            if (Modifier.isPublic(member.getModifiers())\n                    && Modifier.isPublic(member.getDeclaringClass().getModifiers())) {\n\n                return accessible;\n            }\n        }\n        if (!accessible.isAccessible()) {\n            accessible.setAccessible(true);\n        }\n\n        return accessible;\n    }\n\n    // ---------------------------------------------------------------------\n    // Fluent Reflection API\n    // ---------------------------------------------------------------------\n\n    /**\n     * 将给定字符串的开头改为小写.\n     *\n     * @param string\n     * @return\n     */\n    private static String property(String string) {\n        int length = string.length();\n\n        if (length == 0) {\n            return \"\";\n        } else if (length == 1) {\n            return string.toLowerCase();\n        } else {\n            return string.substring(0, 1).toLowerCase() + string.substring(1);\n        }\n    }\n\n    private static Reflect on(Constructor<?> constructor, Object... args) throws ReflectException {\n        try {\n            return on(accessible(constructor).newInstance(args));\n        } catch (Exception e) {\n            throw new ReflectException(e);\n        }\n    }\n\n    private static Reflect on(Method method, Object object, Object... args) throws ReflectException {\n        try {\n            accessible(method);\n\n            if (method.getReturnType() == void.class) {\n                method.invoke(object, args);\n                return on(object);\n            } else {\n                return on(method.invoke(object, args));\n            }\n        } catch (Exception e) {\n            throw new ReflectException(e);\n        }\n    }\n\n    /**\n     * 取得内部维护的对象.\n     */\n    private static Object unwrap(Object object) {\n        if (object instanceof Reflect) {\n            return ((Reflect) object).get();\n        }\n\n        return object;\n    }\n\n    /**\n     * 将Object数组转换为其类型的数组. 如果对象中包含null,我们用NULL.class代替.\n     *\n     * @see Object#getClass()\n     */\n    private static Class<?>[] types(Object... values) {\n        if (values == null) {\n            return new Class[0];\n        }\n\n        Class<?>[] result = new Class[values.length];\n\n        for (int i = 0; i < values.length; i++) {\n            Object value = values[i];\n            result[i] = value == null ? NULL.class : value.getClass();\n        }\n\n        return result;\n    }\n\n    /**\n     * 取得一个类,此操作会初始化类的static区域.\n     *\n     * @see Class#forName(String)\n     */\n    private static Class<?> forName(String name) throws ReflectException {\n        try {\n            return Class.forName(name);\n        } catch (Exception e) {\n            throw new ReflectException(e);\n        }\n    }\n\n    private static Class<?> forName(String name, ClassLoader classLoader) throws ReflectException {\n        try {\n            return Class.forName(name, true, classLoader);\n        } catch (Exception e) {\n            throw new ReflectException(e);\n        }\n    }\n\n    /**\n     * 如果给定的Class是原始类型,那么将其包装为对象类型, 否则返回本身.\n     */\n    public static Class<?> wrapper(Class<?> type) {\n        if (type == null) {\n            return null;\n        } else if (type.isPrimitive()) {\n            if (boolean.class == type) {\n                return Boolean.class;\n            } else if (int.class == type) {\n                return Integer.class;\n            } else if (long.class == type) {\n                return Long.class;\n            } else if (short.class == type) {\n                return Short.class;\n            } else if (byte.class == type) {\n                return Byte.class;\n            } else if (double.class == type) {\n                return Double.class;\n            } else if (float.class == type) {\n                return Float.class;\n            } else if (char.class == type) {\n                return Character.class;\n            } else if (void.class == type) {\n                return Void.class;\n            }\n        }\n\n        return type;\n    }\n\n    /**\n     * 取得内部维护的实际对象\n     *\n     * @param <T>\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> T get() {\n        return (T) object;\n    }\n\n    /**\n     * 设置指定字段为指定值\n     *\n     * @param name\n     * @param value\n     * @return\n     * @throws ReflectException\n     */\n    public Reflect set(String name, Object value) throws ReflectException {\n        try {\n            Field field = field0(name);\n            field.setAccessible(true);\n            field.set(object, unwrap(value));\n            return this;\n        } catch (Exception e) {\n            throw new ReflectException(e);\n        }\n    }\n\n    /**\n     * @param name name\n     * @param <T>  type\n     * @return object\n     * @throws ReflectException\n     */\n    public <T> T get(String name) throws ReflectException {\n        return field(name).get();\n    }\n\n    /**\n     * 取得指定名称的字段\n     *\n     * @param name name\n     * @return reflect\n     * @throws ReflectException\n     */\n    public Reflect field(String name) throws ReflectException {\n        try {\n            Field field = field0(name);\n            return on(field.get(object));\n        } catch (Exception e) {\n            throw new ReflectException(object.getClass().getName(), e);\n        }\n    }\n\n    private Field field0(String name) throws ReflectException {\n        Class<?> type = type();\n\n        // 先尝试取得公有字段\n        try {\n            return type.getField(name);\n        }\n\n        // 此时尝试非公有字段\n        catch (NoSuchFieldException e) {\n            do {\n                try {\n                    return accessible(type.getDeclaredField(name));\n                } catch (NoSuchFieldException ignore) {\n                }\n\n                type = type.getSuperclass();\n            } while (type != null);\n\n            throw new ReflectException(e);\n        }\n    }\n\n    /**\n     * 取得一个Map,map中的key为字段名,value为字段对应的反射工具类\n     *\n     * @return Map\n     */\n    public Map<String, Reflect> fields() {\n        Map<String, Reflect> result = new LinkedHashMap<String, Reflect>();\n        Class<?> type = type();\n\n        do {\n            for (Field field : type.getDeclaredFields()) {\n                if (!isClass ^ Modifier.isStatic(field.getModifiers())) {\n                    String name = field.getName();\n\n                    if (!result.containsKey(name))\n                        result.put(name, field(name));\n                }\n            }\n\n            type = type.getSuperclass();\n        } while (type != null);\n\n        return result;\n    }\n\n    /**\n     * 调用指定的无参数方法\n     *\n     * @param name\n     * @return\n     * @throws ReflectException\n     */\n    public Reflect call(String name) throws ReflectException {\n        return call(name, new Object[0]);\n    }\n\n    /**\n     * 调用方法根据传入的参数\n     *\n     * @param name\n     * @param args\n     * @return\n     * @throws ReflectException\n     */\n    public Reflect call(String name, Object... args) throws ReflectException {\n        Class<?>[] types = types(args);\n\n        try {\n            Method method = exactMethod(name, types);\n            return on(method, object, args);\n        } catch (NoSuchMethodException e) {\n            try {\n                Method method = similarMethod(name, types);\n                return on(method, object, args);\n            } catch (NoSuchMethodException e1) {\n                throw new ReflectException(e1);\n            }\n        }\n    }\n\n    public Method exactMethod(String name, Class<?>[] types) throws NoSuchMethodException {\n        Class<?> type = type();\n\n        try {\n            return type.getMethod(name, types);\n        } catch (NoSuchMethodException e) {\n            do {\n                try {\n                    return type.getDeclaredMethod(name, types);\n                } catch (NoSuchMethodException ignore) {\n                }\n\n                type = type.getSuperclass();\n            } while (type != null);\n\n            throw new NoSuchMethodException();\n        }\n    }\n\n    /**\n     * 根据参数和名称匹配方法,如果找不到方法,\n     */\n    private Method similarMethod(String name, Class<?>[] types) throws NoSuchMethodException {\n        Class<?> type = type();\n\n        for (Method method : type.getMethods()) {\n            if (isSimilarSignature(method, name, types)) {\n                return method;\n            }\n        }\n\n        do {\n            for (Method method : type.getDeclaredMethods()) {\n                if (isSimilarSignature(method, name, types)) {\n                    return method;\n                }\n            }\n\n            type = type.getSuperclass();\n        } while (type != null);\n\n        throw new NoSuchMethodException(\"No similar method \" + name + \" with params \" + Arrays.toString(types)\n                + \" could be found on type \" + type() + \".\");\n    }\n\n    private boolean isSimilarSignature(Method possiblyMatchingMethod, String desiredMethodName,\n                                       Class<?>[] desiredParamTypes) {\n        return possiblyMatchingMethod.getName().equals(desiredMethodName)\n                && match(possiblyMatchingMethod.getParameterTypes(), desiredParamTypes);\n    }\n\n    /**\n     * 创建一个实例通过默认构造器\n     *\n     * @return Reflect\n     * @throws ReflectException\n     */\n    public Reflect create() throws ReflectException {\n        return create(new Object[0]);\n    }\n\n    /**\n     * 创建一个实例根据传入的参数\n     *\n     * @param args 参数\n     * @return Reflect\n     * @throws ReflectException\n     */\n    public Reflect create(Object... args) throws ReflectException {\n        Class<?>[] types = types(args);\n\n        try {\n            Constructor<?> constructor = type().getDeclaredConstructor(types);\n            return on(constructor, args);\n        } catch (NoSuchMethodException e) {\n            for (Constructor<?> constructor : type().getDeclaredConstructors()) {\n                if (match(constructor.getParameterTypes(), types)) {\n                    return on(constructor, args);\n                }\n            }\n\n            throw new ReflectException(e);\n        }\n    }\n\n    /**\n     * 创建一个动态代理根据传入的类型. 如果我们正在维护的是一个Map,那么当调用出现异常时我们将从Map中取值.\n     *\n     * @param proxyType 需要动态代理的类型\n     * @return 动态代理生成的对象\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <P> P as(Class<P> proxyType) {\n        final boolean isMap = (object instanceof Map);\n        final InvocationHandler handler = new InvocationHandler() {\n            \n            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n                String name = method.getName();\n                try {\n                    return on(object).call(name, args).get();\n                } catch (ReflectException e) {\n                    if (isMap) {\n                        Map<String, Object> map = (Map<String, Object>) object;\n                        int length = (args == null ? 0 : args.length);\n\n                        if (length == 0 && name.startsWith(\"get\")) {\n                            return map.get(property(name.substring(3)));\n                        } else if (length == 0 && name.startsWith(\"is\")) {\n                            return map.get(property(name.substring(2)));\n                        } else if (length == 1 && name.startsWith(\"set\")) {\n                            map.put(property(name.substring(3)), args[0]);\n                            return null;\n                        }\n                    }\n\n                    throw e;\n                }\n            }\n        };\n\n        return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), new Class[]{proxyType}, handler);\n    }\n\n    /**\n     * 检查两个数组的类型是否匹配,如果数组中包含原始类型,将它们转换为对应的包装类型.\n     */\n    private boolean match(Class<?>[] declaredTypes, Class<?>[] actualTypes) {\n        if (declaredTypes.length == actualTypes.length) {\n            for (int i = 0; i < actualTypes.length; i++) {\n                if (actualTypes[i] == NULL.class)\n                    continue;\n\n                if (wrapper(declaredTypes[i]).isAssignableFrom(wrapper(actualTypes[i])))\n                    continue;\n\n                return false;\n            }\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public int hashCode() {\n        return object.hashCode();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public boolean equals(Object obj) {\n        return obj instanceof Reflect && object.equals(((Reflect) obj).get());\n\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    public String toString() {\n        return object.toString();\n    }\n\n    /**\n     * 取得我们正在反射的对象的类型.\n     *\n     * @see Object#getClass()\n     */\n    public Class<?> type() {\n        if (isClass) {\n            return (Class<?>) object;\n        } else {\n            return object.getClass();\n        }\n    }\n\n    public static String getMethodDetails(Method method) {\n        StringBuilder sb = new StringBuilder(40);\n        sb.append(Modifier.toString(method.getModifiers()))\n                .append(\" \")\n                .append(method.getReturnType().getName())\n                .append(\" \")\n                .append(method.getName())\n                .append(\"(\");\n        Class<?>[] parameters = method.getParameterTypes();\n        for (Class<?> parameter : parameters) {\n            sb.append(parameter.getName()).append(\", \");\n        }\n        if (parameters.length > 0) {\n            sb.delete(sb.length() - 2, sb.length());\n        }\n        sb.append(\")\");\n        return sb.toString();\n    }\n\n\n    /**\n     * 用来表示null的类.\n     *\n     * @author Lody\n     */\n    private static class NULL {\n    }\n\n    /**\n     * 智能调用 但是只调用类本身声明方法 按照优先级 匹配\n     * <p>\n     * 1.完全匹配\n     * 2.形参 Object...\n     * 3.名字相同 无参数\n     *\n     * @param name\n     * @param args\n     * @return\n     * @throws ReflectException\n     */\n    public Reflect callBest(String name, Object... args) throws ReflectException {\n        Class<?>[] types = types(args);\n        Class<?> type = type();\n\n        Method bestMethod = null;\n        int level = 0;\n        for (Method method : type.getDeclaredMethods()) {\n            if (isSimilarSignature(method, name, types)) {\n                bestMethod = method;\n                level = 2;\n                break;\n            }\n            if (matchObjectMethod(method, name, types)) {\n                bestMethod = method;\n                level = 1;\n                continue;\n            }\n            if (method.getName().equals(name) && method.getParameterTypes().length == 0 && level == 0) {\n                bestMethod = method;\n            }\n        }\n        if (bestMethod != null) {\n            if (level == 0) {\n                args = new Object[0];\n            }\n            if (level == 1) {\n                Object[] args2 = {args};\n                args = args2;\n            }\n            return on(bestMethod, object, args);\n        } else {\n            throw new ReflectException(\"no method found for \" + name, new NoSuchMethodException(\"No best method \" + name + \" with params \" + Arrays.toString(types)\n                    + \" could be found on type \" + type() + \".\"));\n        }\n    }\n\n    private boolean matchObjectMethod(Method possiblyMatchingMethod, String desiredMethodName,\n                                      Class<?>[] desiredParamTypes) {\n        return possiblyMatchingMethod.getName().equals(desiredMethodName)\n                && matchObject(possiblyMatchingMethod.getParameterTypes());\n    }\n\n    private boolean matchObject(Class<?>[] parameterTypes) {\n        Class<Object[]> c = Object[].class;\n        return parameterTypes.length > 0 && parameterTypes[0].isAssignableFrom(c);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/ReflectException.java",
    "content": "package com.lody.virtual.helper.utils;\n\n/**\n * @author Lody\n */\npublic class ReflectException extends RuntimeException {\n\n\tpublic ReflectException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic ReflectException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/SchedulerTask.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.os.Handler;\n\n/**\n * @author Lody\n */\n\npublic abstract class SchedulerTask implements Runnable {\n    private Handler mHandler;\n    private long mDelay;\n\n    public SchedulerTask(Handler handler, long delay) {\n        this.mHandler = handler;\n        this.mDelay = delay;\n    }\n\n    public void schedule() {\n        mHandler.post(mInnerRunnable);\n    }\n\n    public void cancel() {\n        mHandler.removeCallbacks(mInnerRunnable);\n    }\n\n    private final Runnable mInnerRunnable = new Runnable() {\n        @Override\n        public void run() {\n            SchedulerTask.this.run();\n            if(mDelay > 0) {\n                mHandler.postDelayed(this, mDelay);\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/Singleton.java",
    "content": "package com.lody.virtual.helper.utils;\n\n/**\n * Singleton helper class for lazily initialization.\n *\n * Modeled after frameworks/base/include/utils/Singleton.h\n *\n * @hide\n */\npublic abstract class Singleton<T> {\n    private T mInstance;\n\n    protected abstract T create();\n\n    public final T get() {\n        synchronized (this) {\n            if (mInstance == null) {\n                mInstance = create();\n            }\n            return mInstance;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/VLog.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport java.util.Set;\n\n/**\n * @author Lody\n *\n */\npublic class VLog {\n\n\tpublic static boolean OPEN_LOG = true;\n\n\tpublic static void i(String tag, String msg, Object... format) {\n\t\tif (OPEN_LOG) {\n\t\t\tLog.i(tag, String.format(msg, format));\n\t\t}\n\t}\n\n\tpublic static void d(String tag, String msg, Object... format) {\n\t\tif (OPEN_LOG) {\n\t\t\tLog.d(tag, String.format(msg, format));\n\t\t}\n\t}\n\n\tpublic static void w(String tag, String msg, Object... format) {\n\t\tif (OPEN_LOG) {\n\t\t\tLog.w(tag, String.format(msg, format));\n\t\t}\n\t}\n\n\tpublic static void e(String tag, String msg, Object... format) {\n\t\tif (OPEN_LOG) {\n\t\t\tLog.e(tag, String.format(msg, format));\n\t\t}\n\t}\n\n\tpublic static void v(String tag, String msg, Object... format) {\n\t\tif (OPEN_LOG) {\n\t\t\tLog.v(tag, String.format(msg, format));\n\t\t}\n\t}\n\n\tpublic static String toString(Bundle bundle){\n\t\tif(bundle==null)return null;\n\t\tif(Reflect.on(bundle).get(\"mParcelledData\")!=null){\n\t\t\tSet<String> keys=bundle.keySet();\n\t\t\tStringBuilder stringBuilder=new StringBuilder(\"Bundle[\");\n\t\t\tif(keys!=null) {\n\t\t\t\tfor (String key : keys) {\n\t\t\t\t\tstringBuilder.append(key);\n\t\t\t\t\tstringBuilder.append(\"=\");\n\t\t\t\t\tstringBuilder.append(bundle.get(key));\n\t\t\t\t\tstringBuilder.append(\",\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tstringBuilder.append(\"]\");\n\t\t\treturn stringBuilder.toString();\n\t\t}\n\t\treturn bundle.toString();\n\t}\n\n\tpublic static String getStackTraceString(Throwable tr) {\n\t\treturn Log.getStackTraceString(tr);\n\t}\n\n\tpublic static void printStackTrace(String tag) {\n\t\tLog.e(tag, getStackTraceString(new Exception()));\n\t}\n\n\tpublic static void e(String tag, Throwable e) {\n\t\tLog.e(tag, getStackTraceString(e));\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/XmlSerializerAndParser.java",
    "content": "package com.lody.virtual.helper.utils;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\n\npublic interface XmlSerializerAndParser<T> {\n    void writeAsXml(T item, XmlSerializer out) throws IOException;\n    T createFromXml(XmlPullParser parser) throws IOException, XmlPullParserException;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/marks/FakeDeviceMark.java",
    "content": "package com.lody.virtual.helper.utils.marks;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.SOURCE)\npublic @interface FakeDeviceMark {\n    String value() default \"\";\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/marks/FakeLocMark.java",
    "content": "package com.lody.virtual.helper.utils.marks;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.SOURCE)\npublic @interface FakeLocMark {\n    String value() default \"\";\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/os/VBinder.java",
    "content": "package com.lody.virtual.os;\n\nimport android.os.Binder;\n\nimport com.lody.virtual.client.ipc.VActivityManager;\n\n/**\n * @author Lody\n */\n\npublic class VBinder {\n\n    public static int getCallingUid() {\n        return VActivityManager.get().getUidByPid(Binder.getCallingPid());\n    }\n\n    public static int getBaseCallingUid() {\n        return VUserHandle.getAppId(getCallingUid());\n    }\n\n    public static int getCallingPid() {\n        return Binder.getCallingPid();\n    }\n\n    public static VUserHandle getCallingUserHandle() {\n        return new VUserHandle(VUserHandle.getUserId(getCallingUid()));\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java",
    "content": "package com.lody.virtual.os;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Environment;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.EncodeUtils;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.io.File;\nimport java.util.Locale;\n\nimport mirror.dalvik.system.VMRuntime;\n\n/**\n * @author Lody\n */\n\npublic class VEnvironment {\n\n    private static final String TAG = VEnvironment.class.getSimpleName();\n\n    private static final File ROOT;\n    private static final File DATA_DIRECTORY;\n    private static final File USER_DIRECTORY;\n    private static final File DALVIK_CACHE_DIRECTORY;\n\n    static {\n        File host = new File(getContext().getApplicationInfo().dataDir);\n        // Point to: /\n        ROOT = ensureCreated(new File(host, \"virtual\"));\n        // Point to: /data/\n        DATA_DIRECTORY = ensureCreated(new File(ROOT, \"data\"));\n        // Point to: /data/user/\n        USER_DIRECTORY = ensureCreated(new File(DATA_DIRECTORY, \"user\"));\n        // Point to: /opt/\n        DALVIK_CACHE_DIRECTORY = ensureCreated(new File(ROOT, \"opt\"));\n    }\n\n    public static void systemReady() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            try {\n                FileUtils.chmod(ROOT.getAbsolutePath(), FileUtils.FileMode.MODE_755);\n                FileUtils.chmod(DATA_DIRECTORY.getAbsolutePath(), FileUtils.FileMode.MODE_755);\n                FileUtils.chmod(getDataAppDirectory().getAbsolutePath(), FileUtils.FileMode.MODE_755);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n\n    private static Context getContext() {\n        return VirtualCore.get().getContext();\n    }\n\n    private static File ensureCreated(File folder) {\n        if (!folder.exists() && !folder.mkdirs()) {\n            VLog.w(TAG, \"Unable to create the directory: %s.\", folder.getPath());\n        }\n        return folder;\n    }\n\n    public static File getDataUserPackageDirectory(int userId,\n                                                   String packageName) {\n        return ensureCreated(new File(getUserSystemDirectory(userId), packageName));\n    }\n\n    public static File getPackageResourcePath(String packgeName) {\n        return new File(getDataAppPackageDirectory(packgeName),\n                EncodeUtils.decode(\"YmFzZS5hcGs=\")); // base.apk\n    }\n\n    public static File getDataAppDirectory() {\n        return ensureCreated(new File(getDataDirectory(), \"app\"));\n    }\n\n    public static File getUidListFile() {\n        return new File(getSystemSecureDirectory(), \"uid-list.ini\");\n    }\n\n    public static File getBakUidListFile() {\n        return new File(getSystemSecureDirectory(), \"uid-list.ini.bak\");\n    }\n\n    public static File getAccountConfigFile() {\n        return new File(getSystemSecureDirectory(), \"account-list.ini\");\n    }\n\n    public static File getVirtualLocationFile() {\n        return new File(getSystemSecureDirectory(), \"virtual-loc.ini\");\n    }\n\n    public static File getDeviceInfoFile() {\n        return new File(getSystemSecureDirectory(), \"device-info.ini\");\n    }\n\n    public static File getPackageListFile() {\n        return new File(getSystemSecureDirectory(), \"packages.ini\");\n    }\n\n    /**\n     * @return Virtual storage config file\n     */\n    public static File getVSConfigFile() {\n        return new File(getSystemSecureDirectory(), \"vss.ini\");\n    }\n\n    public static File getBakPackageListFile() {\n        return new File(getSystemSecureDirectory(), \"packages.ini.bak\");\n    }\n\n\n    public static File getJobConfigFile() {\n        return new File(getSystemSecureDirectory(), \"job-list.ini\");\n    }\n\n    public static File getDalvikCacheDirectory() {\n        return DALVIK_CACHE_DIRECTORY;\n    }\n\n    public static File getOdexFile(String packageName) {\n        if (isAndroidO()) {\n            // in Android O, the oatfile is relate with classloader, we must ensure the correct location to avoid repeated load dex.\n            String instructionSet = VMRuntime.getCurrentInstructionSet.call();\n            File oatDir = ensureCreated(new File(getDataAppPackageDirectory(packageName), \"oat\" + File.separator + instructionSet));\n            return new File(oatDir, EncodeUtils.decode(\"YmFzZS5vZGV4\")); // base.odex\n        } else {\n            // return new File(DALVIK_CACHE_DIRECTORY, \"data@app@\" + packageName + \"-1@base.apk@classes.dex\");\n            return new File(DALVIK_CACHE_DIRECTORY, EncodeUtils.decode(\"ZGF0YUBhcHBA\") +\n                    packageName +\n                    EncodeUtils.decode(\"LTFAYmFzZS5hcGtAY2xhc3Nlcy5kZXg=\"));\n        }\n    }\n\n    public static File getDataAppPackageDirectory(String packageName) {\n        return ensureCreated(new File(getDataAppDirectory(), packageName));\n    }\n\n    public static File getAppLibDirectory(String packageName) {\n        return ensureCreated(new File(getDataAppPackageDirectory(packageName), \"lib\"));\n    }\n\n    public static File getPackageCacheFile(String packageName) {\n        return new File(getDataAppPackageDirectory(packageName), \"package.ini\");\n    }\n\n    public static File getSignatureFile(String packageName) {\n        return new File(getDataAppPackageDirectory(packageName), \"signature.ini\");\n    }\n\n    public static File getUserSystemDirectory() {\n        return USER_DIRECTORY;\n    }\n\n    public static File getUserSystemDirectory(int userId) {\n        return new File(USER_DIRECTORY, String.valueOf(userId));\n    }\n\n    public static File getVirtualStorageBaseDir() {\n        File externalFilesRoot = Environment.getExternalStorageDirectory();\n        if (externalFilesRoot != null) {\n            File vBaseDir = new File(externalFilesRoot, \"VirtualXposed\");\n            File vSdcard = new File(vBaseDir, \"vsdcard\");\n            return ensureCreated(vSdcard);\n        }\n        return null;\n    }\n\n    public static File getVirtualStorageDir(String packageName, int userId) {\n        File virtualStorageBaseDir = getVirtualStorageBaseDir();\n        // Apps may share sdcard files, we can not separate them by package.\n        if (virtualStorageBaseDir == null) {\n            return null;\n        }\n        File userBase = new File(virtualStorageBaseDir, String.valueOf(userId));\n        return ensureCreated(userBase);\n    }\n\n    // /sdcard/Android/data/<host_package>/virtual/<user>\n    public static File getVirtualPrivateStorageDir(int userId) {\n        String base = String.format(Locale.ENGLISH, \"%s/Android/data/%s/%s/%d\", Environment.getExternalStorageDirectory(),\n                VirtualCore.get().getHostPkg(), \"virtual\", userId);\n        File file = new File(base);\n        return ensureCreated(file);\n    }\n\n    public static File getVirtualPrivateStorageDir(int userId, String packageName) {\n        File file = new File(getVirtualPrivateStorageDir(userId), packageName);\n        return ensureCreated(file);\n    }\n\n    public static File getWifiMacFile(int userId) {\n        // return new File(getUserSystemDirectory(userId), \"wifiMacAddress\");\n        return new File(getUserSystemDirectory(userId), EncodeUtils.decode(\"d2lmaU1hY0FkZHJlc3M=\"));\n    }\n\n    public static File getDataDirectory() {\n        return DATA_DIRECTORY;\n    }\n\n    public static File getSystemSecureDirectory() {\n        return ensureCreated(new File(getDataAppDirectory(), \"system\"));\n    }\n\n    public static File getPackageInstallerStageDir() {\n        return ensureCreated(new File(DATA_DIRECTORY, \".session_dir\"));\n    }\n\n    public static boolean isAndroidO() {\n        return Build.VERSION.SDK_INT > 25;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserHandle.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.os;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.Process;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.client.VClientImpl;\n\nimport java.io.PrintWriter;\n\n/**\n * Representation of a user on the device.\n */\npublic final class VUserHandle implements Parcelable {\n    /**\n     * @hide Range of uids allocated for a user.\n     */\n    public static final int PER_USER_RANGE = 100000;\n\n    /** @hide A user id to indicate all users on the device */\n    public static final int USER_ALL = -1;\n\n    /** @hide A user handle to indicate all users on the device */\n    public static final VUserHandle ALL = new VUserHandle(USER_ALL);\n\n    /** @hide A user id to indicate the currently active user */\n    public static final int USER_CURRENT = -2;\n\n    /** @hide A user handle to indicate the current user of the device */\n    public static final VUserHandle CURRENT = new VUserHandle(USER_CURRENT);\n\n    /** @hide A user id to indicate that we would like to send to the current\n     *  user, but if this is calling from a user process then we will send it\n     *  to the caller's user instead of failing with a security exception */\n    public static final int USER_CURRENT_OR_SELF = -3;\n\n    /** @hide A user handle to indicate that we would like to send to the current\n     *  user, but if this is calling from a user process then we will send it\n     *  to the caller's user instead of failing with a security exception */\n    public static final VUserHandle CURRENT_OR_SELF = new VUserHandle(USER_CURRENT_OR_SELF);\n\n    /** @hide An undefined user id */\n    public static final int USER_NULL = -10000;\n\n    /** @hide A user id constant to indicate the \"owner\" user of the device */\n    public static final int USER_OWNER = 0;\n\n    /** @hide A user handle to indicate the primary/owner user of the device */\n    public static final VUserHandle OWNER = new VUserHandle(USER_OWNER);\n\n    /**\n     * @hide Enable multi-user related side effects. Set this to false if\n     * there are problems with single user use-cases.\n     */\n    public static final boolean MU_ENABLED = true;\n    /**\n     * First gid for applications to share resources. Used when forward-locking\n     * is enabled but all UserHandles need to be able to read the resources.\n     * @hide\n     */\n    public static final int FIRST_SHARED_APPLICATION_GID = 50000;\n    /**\n     * Last gid for applications to share resources. Used when forward-locking\n     * is enabled but all UserHandles need to be able to read the resources.\n     * @hide\n     */\n    public static final int LAST_SHARED_APPLICATION_GID = 59999;\n    /**\n     * First vuid used for fully isolated sandboxed processes (with no permissions of their own)\n     * @hide\n     */\n    public static final int FIRST_ISOLATED_UID = 99000;\n    /**\n     * Last vuid used for fully isolated sandboxed processes (with no permissions of their own)\n     * @hide\n     */\n    public static final int LAST_ISOLATED_UID = 99999;\n    public static final Parcelable.Creator<VUserHandle> CREATOR\n            = new Parcelable.Creator<VUserHandle>() {\n        public VUserHandle createFromParcel(Parcel in) {\n            return new VUserHandle(in);\n        }\n\n        public VUserHandle[] newArray(int size) {\n            return new VUserHandle[size];\n        }\n    };\n    private static final SparseArray<VUserHandle> userHandles = new SparseArray<VUserHandle>();\n    final int mHandle;\n\n    /** @hide */\n    public VUserHandle(int h) {\n        mHandle = h;\n    }\n\n\n    /**\n     * Instantiate a new VUserHandle from the data in a Parcel that was\n     * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you\n     * must not use this with data written by\n     * {@link #writeToParcel(VUserHandle, Parcel)} since it is not possible\n     * to handle a null VUserHandle here.\n     *\n     * @param in The Parcel containing the previously written VUserHandle,\n     * positioned at the location in the buffer where it was written.\n     */\n    public VUserHandle(Parcel in) {\n        mHandle = in.readInt();\n    }\n\n    /**\n     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same\n     * user.\n     * @hide\n     */\n    public static boolean isSameUser(int uid1, int uid2) {\n        return getUserId(uid1) == getUserId(uid2);\n    }\n\n    public static boolean accept(int userId) {\n        if (userId == USER_ALL || userId == myUserId()) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the\n     * uids.\n     * @param uid1 vuid to compare\n     * @param uid2 other vuid to compare\n     * @return whether the appId is the same for both uids\n     * @hide\n     */\n    public static final boolean isSameApp(int uid1, int uid2) {\n        return getAppId(uid1) == getAppId(uid2);\n    }\n\n    /** @hide */\n    public static final boolean isIsolated(int uid) {\n        if (uid > 0) {\n            final int appId = getAppId(uid);\n            return appId >= FIRST_ISOLATED_UID && appId <= LAST_ISOLATED_UID;\n        } else {\n            return false;\n        }\n    }\n\n    /** @hide */\n    public static boolean isApp(int uid) {\n        if (uid > 0) {\n            final int appId = getAppId(uid);\n            return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * Returns the user id for a given vuid.\n     * @hide\n     */\n    public static int getUserId(int uid) {\n        if (MU_ENABLED) {\n            return uid / PER_USER_RANGE;\n        } else {\n            return 0;\n        }\n    }\n\n    /** @hide */\n    public static int getCallingUserId() {\n        return getUserId(VBinder.getCallingUid());\n    }\n\n    /**\n     * Generate a text representation of the vuid, breaking out its individual\n     * components -- user, app, isolated, etc.\n     * @hide\n     */\n\n    /** @hide */\n    public static VUserHandle getCallingUserHandle() {\n        int userId = getUserId(VBinder.getCallingUid());\n        VUserHandle userHandle = userHandles.get(userId);\n        // Intentionally not synchronized to save time\n        if (userHandle == null) {\n            userHandle = new VUserHandle(userId);\n            userHandles.put(userId, userHandle);\n        }\n        return userHandle;\n    }\n\n    /**\n     * Returns the vuid that is composed from the userId and the appId.\n     * @hide\n     */\n    public static int getUid(int userId, int appId) {\n        if (MU_ENABLED) {\n            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);\n        } else {\n            return appId;\n        }\n    }\n\n    /**\n     * Returns the app id (or base vuid) for a given vuid, stripping out the user id from it.\n     * @hide\n     */\n    public static int getAppId(int uid) {\n        return uid % PER_USER_RANGE;\n    }\n\n    public static int myAppId() {\n        return getAppId(VClientImpl.get().getVUid());\n    }\n\n    /**\n     * Returns the app id for a given shared app gid.\n     * @hide\n     */\n    public static int getAppIdFromSharedAppGid(int gid) {\n        final int noUserGid = getAppId(gid);\n        if (noUserGid < FIRST_SHARED_APPLICATION_GID ||\n                noUserGid > LAST_SHARED_APPLICATION_GID) {\n            throw new IllegalArgumentException(Integer.toString(gid) + \" is not a shared app gid\");\n        }\n        return (noUserGid + Process.FIRST_APPLICATION_UID) - FIRST_SHARED_APPLICATION_GID;\n    }\n\n    public static void formatUid(StringBuilder sb, int uid) {\n        if (uid < Process.FIRST_APPLICATION_UID) {\n            sb.append(uid);\n        } else {\n            sb.append('u');\n            sb.append(getUserId(uid));\n            final int appId = getAppId(uid);\n            if (appId >= FIRST_ISOLATED_UID && appId <= LAST_ISOLATED_UID) {\n                sb.append('i');\n                sb.append(appId - FIRST_ISOLATED_UID);\n            } else if (appId >= Process.FIRST_APPLICATION_UID) {\n                sb.append('a');\n                sb.append(appId - Process.FIRST_APPLICATION_UID);\n            } else {\n                sb.append('s');\n                sb.append(appId);\n            }\n        }\n    }\n\n    /**\n     * Generate a text representation of the vuid, breaking out its individual\n     * components -- user, app, isolated, etc.\n     * @hide\n     */\n    public static String formatUid(int uid) {\n        StringBuilder sb = new StringBuilder();\n        formatUid(sb, uid);\n        return sb.toString();\n    }\n\n    /**\n     * Generate a text representation of the vuid, breaking out its individual\n     * components -- user, app, isolated, etc.\n     * @hide\n     */\n    public static void formatUid(PrintWriter pw, int uid) {\n        if (uid < Process.FIRST_APPLICATION_UID) {\n            pw.print(uid);\n        } else {\n            pw.print('u');\n            pw.print(getUserId(uid));\n            final int appId = getAppId(uid);\n            if (appId >= FIRST_ISOLATED_UID && appId <= LAST_ISOLATED_UID) {\n                pw.print('i');\n                pw.print(appId - FIRST_ISOLATED_UID);\n            } else if (appId >= Process.FIRST_APPLICATION_UID) {\n                pw.print('a');\n                pw.print(appId - Process.FIRST_APPLICATION_UID);\n            } else {\n                pw.print('s');\n                pw.print(appId);\n            }\n        }\n    }\n\n    /**\n     * Returns the user id of the current process\n     * @return user id of the current process\n     * @hide\n     */\n    public static int myUserId() {\n        return getUserId(VClientImpl.get().getVUid());\n    }\n\n    /**\n     * Write a VUserHandle to a Parcel, handling null pointers.  Must be\n     * read with {@link #readFromParcel(Parcel)}.\n     *\n     * @param h The VUserHandle to be written.\n     * @param out The Parcel in which the VUserHandle will be placed.\n     *\n     * @see #readFromParcel(Parcel)\n     */\n    public static void writeToParcel(VUserHandle h, Parcel out) {\n        if (h != null) {\n            h.writeToParcel(out, 0);\n        } else {\n            out.writeInt(USER_NULL);\n        }\n    }\n\n    /**\n     * Read a VUserHandle from a Parcel that was previously written\n     * with {@link #writeToParcel(VUserHandle, Parcel)}, returning either\n     * a null or new object as appropriate.\n     *\n     * @param in The Parcel from which to read the VUserHandle\n     * @return Returns a new VUserHandle matching the previously written\n     * object, or null if a null had been written.\n     *\n     * @see #writeToParcel(VUserHandle, Parcel)\n     */\n    public static VUserHandle readFromParcel(Parcel in) {\n        int h = in.readInt();\n        return h != USER_NULL ? new VUserHandle(h) : null;\n    }\n\n    public static VUserHandle myUserHandle() {\n        return new VUserHandle(myUserId());\n    }\n    \n    /**\n     * Returns true if this VUserHandle refers to the owner user; false otherwise.\n     * @return true if this VUserHandle refers to the owner user; false otherwise.\n     * @hide\n     */\n    public final boolean isOwner() {\n        return this.equals(OWNER);\n    }\n\n    /**\n     * Returns the userId stored in this VUserHandle.\n     * @hide\n     */\n    public int getIdentifier() {\n        return mHandle;\n    }\n\n    @Override\n    public String toString() {\n        return \"VUserHandle{\" + mHandle + \"}\";\n    }\n    \n    @Override\n    public boolean equals(Object obj) {\n        try {\n            if (obj != null) {\n                VUserHandle other = (VUserHandle)obj;\n                return mHandle == other.mHandle;\n            }\n        } catch (ClassCastException e) {\n        }\n        return false;\n    }\n    \n    @Override\n    public int hashCode() {\n        return mHandle;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel out, int flags) {\n        out.writeInt(mHandle);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserInfo.java",
    "content": "package com.lody.virtual.os;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * Per-user information.\n */\npublic class VUserInfo implements Parcelable {\n\n    /** 8 bits for user type */\n    public static final int FLAG_MASK_USER_TYPE = 0x000000FF;\n\n    /**\n     * *************************** NOTE ***************************\n     * These flag values CAN NOT CHANGE because they are written\n     * directly to storage.\n     */\n\n    /**\n     * Primary user. Only one user can have this flag set. Meaning of this\n     * flag TBD.\n     */\n    public static final int FLAG_PRIMARY = 0x00000001;\n\n    /**\n     * User with administrative privileges. Such a user can create and\n     * delete users.\n     */\n    public static final int FLAG_ADMIN   = 0x00000002;\n\n    /**\n     * Indicates a guest user that may be transient.\n     */\n    public static final int FLAG_GUEST   = 0x00000004;\n\n    /**\n     * Indicates the user has restrictions in privileges, in addition to those for normal users.\n     * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.\n     */\n    public static final int FLAG_RESTRICTED = 0x00000008;\n\n    /**\n     * Indicates that this user has gone through its first-time initialization.\n     */\n    public static final int FLAG_INITIALIZED = 0x00000010;\n\n    /**\n     * Indicates that this user is a profile of another user, for example holding a users\n     * corporate data.\n     */\n    public static final int FLAG_MANAGED_PROFILE = 0x00000020;\n\n    /**\n     * Indicates that this user is disabled.\n     */\n    public static final int FLAG_DISABLED = 0x00000040;\n\n\n    public static final int NO_PROFILE_GROUP_ID = -1;\n\n    public int id;\n    public int serialNumber;\n    public String name;\n    public String iconPath;\n    public int flags;\n    public long creationTime;\n    public long lastLoggedInTime;\n    public int profileGroupId;\n\n    /** User is only partially created. */\n    public boolean partial;\n\n    public VUserInfo(int id, String name, int flags) {\n        this(id, name, null, flags);\n    }\n\n    public VUserInfo(int id, String name, String iconPath, int flags) {\n        this.id = id;\n        this.name = name;\n        this.flags = flags;\n        this.iconPath = iconPath;\n        this.profileGroupId = NO_PROFILE_GROUP_ID;\n    }\n\n    public boolean isPrimary() {\n        return (flags & FLAG_PRIMARY) == FLAG_PRIMARY;\n    }\n\n    public boolean isAdmin() {\n        return (flags & FLAG_ADMIN) == FLAG_ADMIN;\n    }\n\n    public boolean isGuest() {\n        return (flags & FLAG_GUEST) == FLAG_GUEST;\n    }\n\n    public boolean isRestricted() {\n        return (flags & FLAG_RESTRICTED) == FLAG_RESTRICTED;\n    }\n\n    public boolean isManagedProfile() {\n        return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE;\n    }\n\n    public boolean isEnabled() {\n        return (flags & FLAG_DISABLED) != FLAG_DISABLED;\n    }\n\n    public VUserInfo() {\n    }\n\n    public VUserInfo(VUserInfo orig) {\n        name = orig.name;\n        iconPath = orig.iconPath;\n        id = orig.id;\n        flags = orig.flags;\n        serialNumber = orig.serialNumber;\n        creationTime = orig.creationTime;\n        lastLoggedInTime = orig.lastLoggedInTime;\n        partial = orig.partial;\n        profileGroupId = orig.profileGroupId;\n    }\n\n    @Override\n    public String toString() {\n        return \"UserInfo{\" + id + \":\" + name + \":\" + Integer.toHexString(flags) + \"}\";\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int parcelableFlags) {\n        dest.writeInt(id);\n        dest.writeString(name);\n        dest.writeString(iconPath);\n        dest.writeInt(flags);\n        dest.writeInt(serialNumber);\n        dest.writeLong(creationTime);\n        dest.writeLong(lastLoggedInTime);\n        dest.writeInt(partial ? 1 : 0);\n        dest.writeInt(profileGroupId);\n    }\n\n    public static final Parcelable.Creator<VUserInfo> CREATOR\n            = new Parcelable.Creator<VUserInfo>() {\n        public VUserInfo createFromParcel(Parcel source) {\n            return new VUserInfo(source);\n        }\n        public VUserInfo[] newArray(int size) {\n            return new VUserInfo[size];\n        }\n    };\n\n    private VUserInfo(Parcel source) {\n        id = source.readInt();\n        name = source.readString();\n        iconPath = source.readString();\n        flags = source.readInt();\n        serialNumber = source.readInt();\n        creationTime = source.readLong();\n        lastLoggedInTime = source.readLong();\n        partial = source.readInt() != 0;\n        profileGroupId = source.readInt();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/os/VUserManager.java",
    "content": "package com.lody.virtual.os;\n\nimport android.graphics.Bitmap;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.LocalProxyUtils;\nimport com.lody.virtual.client.ipc.ServiceManagerNative;\nimport com.lody.virtual.server.IUserManager;\n\nimport java.util.List;\n\nimport static com.lody.virtual.client.ipc.ServiceManagerNative.USER;\n\n/**\n * Manages users and user details on a multi-user system.\n */\npublic class VUserManager {\n\n    private static String TAG = \"VUserManager\";\n    private IUserManager mService;\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from adding and removing\n     * accounts.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_MODIFY_ACCOUNTS = \"no_modify_accounts\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from changing Wi-Fi\n     * access points.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_CONFIG_WIFI = \"no_config_wifi\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from installing applications.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_INSTALL_APPS = \"no_install_apps\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from uninstalling applications.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_UNINSTALL_APPS = \"no_uninstall_apps\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from toggling location sharing.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n\n    public static final String DISALLOW_SHARE_LOCATION = \"no_share_location\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from enabling the\n     * \"Unknown Sources\" setting, that allows installation of apps from unknown sources.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = \"no_install_unknown_sources\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from configuring bluetooth.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_CONFIG_BLUETOOTH = \"no_config_bluetooth\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from transferring files over\n     * USB. The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_USB_FILE_TRANSFER = \"no_usb_file_transfer\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from configuring user\n     * credentials. The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_CONFIG_CREDENTIALS = \"no_config_credentials\";\n\n    /**\n     * Key for user restrictions. Specifies if a user is disallowed from removing users.\n     * The default value is <code>false</code>.\n     * <p/>\n     * Type: Boolean\n     */\n    public static final String DISALLOW_REMOVE_USER = \"no_remove_user\";\n\n    private static VUserManager sInstance = null;\n\n    /** @hide */\n    public synchronized static VUserManager get() {\n        if (sInstance == null) {\n            IUserManager remote = IUserManager.Stub.asInterface(ServiceManagerNative.getService(USER));\n            sInstance = new VUserManager(remote);\n        }\n        return sInstance;\n    }\n\n    /** @hide */\n    public VUserManager(IUserManager service) {\n        mService = service;\n    }\n\n    private IUserManager getService() {\n        if (mService == null\n                || (!VirtualCore.get().isVAppProcess() && !mService.asBinder().pingBinder())) {\n            synchronized (this) {\n                Object remote = getStubInterface();\n                mService = LocalProxyUtils.genProxy(IUserManager.class, remote);\n            }\n        }\n        return mService;\n    }\n\n    private Object getStubInterface() {\n        return IUserManager.Stub.asInterface(ServiceManagerNative.getService(USER));\n    }\n\n    /**\n     * Returns whether the system supports multiple users.\n     * @return true if multiple users can be created, false if it is a single user device.\n     * @hide\n     */\n    public static boolean supportsMultipleUsers() {\n        return getMaxSupportedUsers() > 1;\n    }\n\n    /**\n     * Returns the user handle for the user that this application is running for.\n     * @return the user handle of the user making this call.\n     * @hide\n     */\n    public int getUserHandle() {\n        return VUserHandle.myUserId();\n    }\n\n    /**\n     * Returns the user name of the user making this call.  This call is only\n     * available to applications on the system image; it requires the\n     * MANAGE_USERS permission.\n     * @return the user name\n     */\n    public String getUserName() {\n        try {\n            return getService().getUserInfo(getUserHandle()).name;\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get user name\", re);\n            return \"\";\n        }\n    }\n\n   /**\n     * Used to determine whether the user making this call is subject to\n     * teleportations.\n     * @return whether the user making this call is a goat\n     */\n    public boolean isUserAGoat() {\n        return false;\n    }\n\n    /**\n     * Returns the UserInfo object describing a specific user.\n     * @param handle the user handle of the user whose information is being requested.\n     * @return the UserInfo object for a specific user.\n     * @hide\n     */\n    public VUserInfo getUserInfo(int handle) {\n        try {\n            return getService().getUserInfo(handle);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get user info\", re);\n            return null;\n        }\n    }\n\n    /**\n     * Return the serial number for a user.  This is a device-unique\n     * number assigned to that user; if the user is deleted and then a new\n     * user created, the new users will not be given the same serial number.\n     * @param user The user whose serial number is to be retrieved.\n     * @return The serial number of the given user; returns -1 if the\n     * given VUserHandle does not exist.\n     * @see #getUserForSerialNumber(long)\n     */\n    public long getSerialNumberForUser(VUserHandle user) {\n        return getUserSerialNumber(user.getIdentifier());\n    }\n\n    /**\n     * Return the user associated with a serial number previously\n     * returned by {@link #getSerialNumberForUser(VUserHandle)}.\n     * @param serialNumber The serial number of the user that is being\n     * retrieved.\n     * @return Return the user associated with the serial number, or null\n     * if there is not one.\n     * @see #getSerialNumberForUser(VUserHandle)\n     */\n    public VUserHandle getUserForSerialNumber(long serialNumber) {\n        int ident = getUserHandle((int)serialNumber);\n        return ident >= 0 ? new VUserHandle(ident) : null;\n    }\n\n    /**\n     * Creates a user with the specified name and options.\n     *\n     * @param name the user's name\n     * @param flags flags that identify the type of user and other properties.\n     * @see VUserInfo\n     *\n     * @return the UserInfo object for the created user, or null if the user could not be created.\n     * @hide\n     */\n    public VUserInfo createUser(String name, int flags) {\n        try {\n            return getService().createUser(name, flags);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not create a user\", re);\n            return null;\n        }\n    }\n\n    /**\n     * Return the number of users currently created on the device.\n     */\n    public int getUserCount() {\n        List<VUserInfo> users = getUsers();\n        return users != null ? users.size() : 1;\n    }\n\n    /**\n     * Returns information for all users on this device.\n     * @return the list of users that were created.\n     * @hide\n     */\n    public List<VUserInfo> getUsers() {\n        try {\n            return getService().getUsers(false);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get user list\", re);\n            return null;\n        }\n    }\n\n    /**\n     * Returns information for all users on this device.\n     * @param excludeDying specify if the list should exclude users being removed.\n     * @return the list of users that were created.\n     * @hide\n     */\n    public List<VUserInfo> getUsers(boolean excludeDying) {\n        try {\n            return getService().getUsers(excludeDying);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get user list\", re);\n            return null;\n        }\n    }\n\n    /**\n     * Removes a user and all associated data.\n     * @param handle the integer handle of the user, where 0 is the primary user.\n     * @hide\n     */\n    public boolean removeUser(int handle) {\n        try {\n            return getService().removeUser(handle);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not remove user \", re);\n            return false;\n        }\n    }\n\n    /**\n     * Updates the user's name.\n     *\n     * @param handle the user's integer handle\n     * @param name the new name for the user\n     * @hide\n     */\n    public void setUserName(int handle, String name) {\n        try {\n            getService().setUserName(handle, name);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not set the user name \", re);\n        }\n    }\n\n    /**\n     * Sets the user's photo.\n     * @param handle the user for whom to change the photo.\n     * @param icon the bitmap to set as the photo.\n     * @hide\n     */\n    public void setUserIcon(int handle, Bitmap icon) {\n        try {\n            getService().setUserIcon(handle, icon);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not set the user icon \", re);\n        }\n    }\n\n    /**\n     * Returns a file descriptor for the user's photo. PNG data can be read from this file.\n     * @param handle the user whose photo we want to read.\n     * @return a {@link Bitmap} of the user's photo, or null if there's no photo.\n     * @hide\n     */\n    public Bitmap getUserIcon(int handle) {\n        try {\n            return getService().getUserIcon(handle);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get the user icon \", re);\n            return null;\n        }\n    }\n\n    /**\n     * Enable or disable the use of a guest account. If disabled, the existing guest account\n     * will be wiped.\n     * @param enable whether to enable a guest account.\n     * @hide\n     */\n    public void setGuestEnabled(boolean enable) {\n        try {\n            getService().setGuestEnabled(enable);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not change guest account availability to \" + enable);\n        }\n    }\n\n    /**\n     * Checks if a guest user is enabled for this device.\n     * @return whether a guest user is enabled\n     * @hide\n     */\n    public boolean isGuestEnabled() {\n        try {\n            return getService().isGuestEnabled();\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not retrieve guest enabled state\");\n            return false;\n        }\n    }\n\n    /**\n     * Wipes all the data for a user, but doesn't remove the user.\n     * @param handle\n     * @hide\n     */\n    public void wipeUser(int handle) {\n        try {\n            getService().wipeUser(handle);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not wipe user \" + handle);\n        }\n    }\n\n    /**\n     * Returns the maximum number of users that can be created on this device. A return value\n     * of 1 means that it is a single user device.\n     * @hide\n     * @return a value greater than or equal to 1\n     */\n    public static int getMaxSupportedUsers() {\n        return Integer.MAX_VALUE;\n    }\n\n    /**\n     * Returns a serial number on this device for a given VUserHandle. User handles can be recycled\n     * when deleting and creating users, but serial numbers are not reused until the device is wiped.\n     * @param handle\n     * @return a serial number associated with that user, or -1 if the VUserHandle is not valid.\n     * @hide\n     */\n    public int getUserSerialNumber(int handle) {\n        try {\n            return getService().getUserSerialNumber(handle);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get serial number for user \" + handle);\n        }\n        return -1;\n    }\n\n    /**\n     * Returns a VUserHandle on this device for a given user serial number. User handles can be\n     * recycled when deleting and creating users, but serial numbers are not reused until the device\n     * is wiped.\n     * @param userSerialNumber\n     * @return the VUserHandle associated with that user serial number, or -1 if the serial number\n     * is not valid.\n     * @hide\n     */\n    public int getUserHandle(int userSerialNumber) {\n        try {\n            return getService().getUserHandle(userSerialNumber);\n        } catch (RemoteException re) {\n            Log.w(TAG, \"Could not get VUserHandle for user \" + userSerialNumber);\n        }\n        return -1;\n    }\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/AppTaskInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class AppTaskInfo implements Parcelable {\n\tpublic static final Parcelable.Creator<AppTaskInfo> CREATOR = new Parcelable.Creator<AppTaskInfo>() {\n\t\t@Override\n\t\tpublic AppTaskInfo createFromParcel(Parcel source) {\n\t\t\treturn new AppTaskInfo(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic AppTaskInfo[] newArray(int size) {\n\t\t\treturn new AppTaskInfo[size];\n\t\t}\n\t};\n\tpublic int taskId;\n\tpublic Intent baseIntent;\n\tpublic ComponentName baseActivity;\n\tpublic ComponentName topActivity;\n\n\n\tpublic AppTaskInfo(int taskId, Intent baseIntent, ComponentName baseActivity, ComponentName topActivity) {\n\t\tthis.taskId = taskId;\n\t\tthis.baseIntent = baseIntent;\n\t\tthis.baseActivity = baseActivity;\n\t\tthis.topActivity = topActivity;\n\t}\n\n\tprotected AppTaskInfo(Parcel in) {\n\t\ttaskId = in.readInt();\n\t\tbaseIntent = in.readParcelable(Intent.class.getClassLoader());\n\t\tbaseActivity = in.readParcelable(ComponentName.class.getClassLoader());\n\t\ttopActivity = in.readParcelable(ComponentName.class.getClassLoader());\n\t}\n\n\t@Override\n\tpublic int describeContents() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void writeToParcel(Parcel dest, int flags) {\n\t\tdest.writeInt(taskId);\n\t\tdest.writeParcelable(baseIntent, flags);\n\t\tdest.writeParcelable(baseActivity, flags);\n\t\tdest.writeParcelable(topActivity, flags);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/BadgerInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.os.VUserHandle;\n\n/**\n * @author Lody\n */\npublic class BadgerInfo implements Parcelable {\n\n    public int userId;\n    public String packageName;\n    public int badgerCount;\n    public String className;\n\n    public BadgerInfo() {\n        userId = VUserHandle.myUserId();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(userId);\n        dest.writeString(packageName);\n        dest.writeInt(badgerCount);\n        dest.writeString(className);\n    }\n\n    protected BadgerInfo(Parcel in) {\n        userId = in.readInt();\n        packageName = in.readString();\n        badgerCount = in.readInt();\n        className = in.readString();\n    }\n\n    public static final Parcelable.Creator<BadgerInfo> CREATOR = new Parcelable.Creator<BadgerInfo>() {\n        @Override\n        public BadgerInfo createFromParcel(Parcel source) {\n            return new BadgerInfo(source);\n        }\n\n        @Override\n        public BadgerInfo[] newArray(int size) {\n            return new BadgerInfo[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstallResult.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n *\n */\npublic class InstallResult implements Parcelable {\n\n\tpublic static final Creator<InstallResult> CREATOR = new Creator<InstallResult>() {\n\t\t@Override\n\t\tpublic InstallResult createFromParcel(Parcel in) {\n\t\t\treturn new InstallResult(in);\n\t\t}\n\n\t\t@Override\n\t\tpublic InstallResult[] newArray(int size) {\n\t\t\treturn new InstallResult[size];\n\t\t}\n\t};\n\tpublic boolean isSuccess;\n\tpublic boolean isUpdate;\n\tpublic String packageName;\n\tpublic String error;\n\n\tpublic InstallResult() {\n\t}\n\n\tprotected InstallResult(Parcel in) {\n\t\tthis.isSuccess = in.readByte() != 0;\n\t\tthis.isUpdate = in.readByte() != 0;\n\t\tthis.packageName = in.readString();\n\t\tthis.error = in.readString();\n\t}\n\n\tpublic static InstallResult makeFailure(String error) {\n\t\tInstallResult res = new InstallResult();\n\t\tres.error = error;\n\t\treturn res;\n\t}\n\n\t@Override\n\tpublic void writeToParcel(Parcel dest, int flags) {\n\t\tdest.writeByte((byte) (isSuccess ? 1 : 0));\n\t\tdest.writeByte((byte) (isUpdate ? 1 : 0));\n\t\tdest.writeString(packageName);\n\t\tdest.writeString(error);\n\t}\n\n\t@Override\n\tpublic int describeContents() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"InstallResult{\" +\n\t\t\t\t\"isSuccess=\" + isSuccess +\n\t\t\t\t\", isUpdate=\" + isUpdate +\n\t\t\t\t\", packageName='\" + packageName + '\\'' +\n\t\t\t\t\", error='\" + error + '\\'' +\n\t\t\t\t'}';\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstalledAppInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VPackageManager;\nimport com.lody.virtual.os.VEnvironment;\n\nimport java.io.File;\n\n/**\n * @author Lody\n */\npublic final class InstalledAppInfo implements Parcelable {\n\n    public String packageName;\n    public String apkPath;\n    public String libPath;\n    public boolean dependSystem;\n    public int appId;\n    public String[] splitCodePaths;\n\n    public InstalledAppInfo(String packageName, String apkPath, String libPath, boolean dependSystem, boolean skipDexOpt, int appId, String[] splitCodePaths) {\n        this.packageName = packageName;\n        this.apkPath = apkPath;\n        this.libPath = libPath;\n        this.dependSystem = dependSystem;\n        this.appId = appId;\n        this.splitCodePaths = splitCodePaths;\n    }\n\n    public File getOdexFile() {\n        return VEnvironment.getOdexFile(packageName);\n    }\n\n    public ApplicationInfo getApplicationInfo(int userId) {\n        return VPackageManager.get().getApplicationInfo(packageName, 0, userId);\n    }\n\n    public PackageInfo getPackageInfo(int userId) {\n        return VPackageManager.get().getPackageInfo(packageName, 0, userId);\n    }\n\n    public int[] getInstalledUsers() {\n        return VirtualCore.get().getPackageInstalledUsers(packageName);\n    }\n\n    public boolean isLaunched(int userId) {\n        return VirtualCore.get().isPackageLaunched(userId, packageName);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.packageName);\n        dest.writeString(this.apkPath);\n        dest.writeString(this.libPath);\n        dest.writeByte(this.dependSystem ? (byte) 1 : (byte) 0);\n        dest.writeInt(this.appId);\n\n        dest.writeStringArray(this.splitCodePaths);\n    }\n\n    protected InstalledAppInfo(Parcel in) {\n        this.packageName = in.readString();\n        this.apkPath = in.readString();\n        this.libPath = in.readString();\n        this.dependSystem = in.readByte() != 0;\n        this.appId = in.readInt();\n\n        this.splitCodePaths = in.createStringArray();\n    }\n\n    public static final Creator<InstalledAppInfo> CREATOR = new Creator<InstalledAppInfo>() {\n        @Override\n        public InstalledAppInfo createFromParcel(Parcel source) {\n            return new InstalledAppInfo(source);\n        }\n\n        @Override\n        public InstalledAppInfo[] newArray(int size) {\n            return new InstalledAppInfo[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/PendingIntentData.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.app.PendingIntent;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\npublic class PendingIntentData implements Parcelable {\n\n    public static final Creator<PendingIntentData> CREATOR = new Creator<PendingIntentData>() {\n        public final PendingIntentData createFromParcel(Parcel source) {\n            return new PendingIntentData(source);\n        }\n\n        public final PendingIntentData[] newArray(int size) {\n            return new PendingIntentData[size];\n        }\n    };\n    public String creator;\n    public PendingIntent pendingIntent;\n\n    protected PendingIntentData(Parcel source) {\n        this.creator = source.readString();\n        this.pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(source);\n    }\n\n    public PendingIntentData(String creator, IBinder binder) {\n        this.creator = creator;\n        this.pendingIntent = readPendingIntent(binder);\n    }\n\n    public static PendingIntent readPendingIntent(IBinder binder) {\n        Parcel parcel = Parcel.obtain();\n        parcel.writeStrongBinder(binder);\n        parcel.setDataPosition(0);\n        try {\n            return PendingIntent.readPendingIntentOrNullFromParcel(parcel);\n        } finally {\n            parcel.recycle();\n        }\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.creator);\n        this.pendingIntent.writeToParcel(dest, flags);\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/PendingResultData.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.content.BroadcastReceiver;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n\n/**\n * @author Lody\n */\n\npublic class PendingResultData implements Parcelable {\n    public static final Creator<PendingResultData> CREATOR = new Creator<PendingResultData>() {\n        @Override\n        public PendingResultData createFromParcel(Parcel source) {\n            return new PendingResultData(source);\n        }\n\n        @Override\n        public PendingResultData[] newArray(int size) {\n            return new PendingResultData[size];\n        }\n    };\n    public int mType;\n    public boolean mOrderedHint;\n    public boolean mInitialStickyHint;\n    public IBinder mToken;\n    public int mSendingUser;\n    public int mFlags;\n    public int mResultCode;\n    public String mResultData;\n    public Bundle mResultExtras;\n    public boolean mAbortBroadcast;\n    public boolean mFinished;\n\n    public PendingResultData(BroadcastReceiver.PendingResult result) {\n        if (mirror.android.content.BroadcastReceiver.PendingResultMNC.ctor != null) {\n            mType = mirror.android.content.BroadcastReceiver.PendingResultMNC.mType.get(result);\n            mOrderedHint = mirror.android.content.BroadcastReceiver.PendingResultMNC.mOrderedHint.get(result);\n            mInitialStickyHint = mirror.android.content.BroadcastReceiver.PendingResultMNC.mInitialStickyHint.get(result);\n            mToken = mirror.android.content.BroadcastReceiver.PendingResultMNC.mToken.get(result);\n            mSendingUser = mirror.android.content.BroadcastReceiver.PendingResultMNC.mSendingUser.get(result);\n            mFlags = mirror.android.content.BroadcastReceiver.PendingResultMNC.mFlags.get(result);\n            mResultCode = mirror.android.content.BroadcastReceiver.PendingResultMNC.mResultCode.get(result);\n            mResultData = mirror.android.content.BroadcastReceiver.PendingResultMNC.mResultData.get(result);\n            mResultExtras = mirror.android.content.BroadcastReceiver.PendingResultMNC.mResultExtras.get(result);\n            mAbortBroadcast = mirror.android.content.BroadcastReceiver.PendingResultMNC.mAbortBroadcast.get(result);\n            mFinished = mirror.android.content.BroadcastReceiver.PendingResultMNC.mFinished.get(result);\n        } else if (mirror.android.content.BroadcastReceiver.PendingResultJBMR1.ctor != null) {\n            mType = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mType.get(result);\n            mOrderedHint = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mOrderedHint.get(result);\n            mInitialStickyHint = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mInitialStickyHint.get(result);\n            mToken = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mToken.get(result);\n            mSendingUser = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mSendingUser.get(result);\n            mResultCode = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mResultCode.get(result);\n            mResultData = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mResultData.get(result);\n            mResultExtras = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mResultExtras.get(result);\n            mAbortBroadcast = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mAbortBroadcast.get(result);\n            mFinished = mirror.android.content.BroadcastReceiver.PendingResultJBMR1.mFinished.get(result);\n        } else {\n            mType = mirror.android.content.BroadcastReceiver.PendingResult.mType.get(result);\n            mOrderedHint = mirror.android.content.BroadcastReceiver.PendingResult.mOrderedHint.get(result);\n            mInitialStickyHint = mirror.android.content.BroadcastReceiver.PendingResult.mInitialStickyHint.get(result);\n            mToken = mirror.android.content.BroadcastReceiver.PendingResult.mToken.get(result);\n            mResultCode = mirror.android.content.BroadcastReceiver.PendingResult.mResultCode.get(result);\n            mResultData = mirror.android.content.BroadcastReceiver.PendingResult.mResultData.get(result);\n            mResultExtras = mirror.android.content.BroadcastReceiver.PendingResult.mResultExtras.get(result);\n            mAbortBroadcast = mirror.android.content.BroadcastReceiver.PendingResult.mAbortBroadcast.get(result);\n            mFinished = mirror.android.content.BroadcastReceiver.PendingResult.mFinished.get(result);\n        }\n    }\n\n\n    protected PendingResultData(Parcel in) {\n        this.mType = in.readInt();\n        this.mOrderedHint = in.readByte() != 0;\n        this.mInitialStickyHint = in.readByte() != 0;\n        this.mToken = in.readStrongBinder();\n        this.mSendingUser = in.readInt();\n        this.mFlags = in.readInt();\n        this.mResultCode = in.readInt();\n        this.mResultData = in.readString();\n        this.mResultExtras = in.readBundle();\n        this.mAbortBroadcast = in.readByte() != 0;\n        this.mFinished = in.readByte() != 0;\n    }\n\n    public BroadcastReceiver.PendingResult build() {\n        if (mirror.android.content.BroadcastReceiver.PendingResultMNC.ctor != null) {\n            return mirror.android.content.BroadcastReceiver.PendingResultMNC.ctor.newInstance(mResultCode, mResultData, mResultExtras, mType, mOrderedHint, mInitialStickyHint, mToken, mSendingUser, mFlags);\n        }\n        if (mirror.android.content.BroadcastReceiver.PendingResultJBMR1.ctor != null) {\n            return mirror.android.content.BroadcastReceiver.PendingResultJBMR1.ctor.newInstance(mResultCode, mResultData, mResultExtras, mType, mOrderedHint, mInitialStickyHint, mToken, mSendingUser);\n        }\n        return mirror.android.content.BroadcastReceiver.PendingResult.ctor.newInstance(mResultCode, mResultData, mResultExtras, mType, mOrderedHint, mInitialStickyHint, mToken);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.mType);\n        dest.writeByte(this.mOrderedHint ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.mInitialStickyHint ? (byte) 1 : (byte) 0);\n        dest.writeStrongBinder(this.mToken);\n        dest.writeInt(this.mSendingUser);\n        dest.writeInt(this.mFlags);\n        dest.writeInt(this.mResultCode);\n        dest.writeString(this.mResultData);\n        dest.writeBundle(this.mResultExtras);\n        dest.writeByte(this.mAbortBroadcast ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.mFinished ? (byte) 1 : (byte) 0);\n    }\n\n    public void finish() {\n        try {\n            build().finish();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/Problem.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n *\n */\npublic class Problem implements Parcelable {\n\tpublic static final Creator<Problem> CREATOR = new Creator<Problem>() {\n\t\tpublic Problem createFromParcel(Parcel source) {\n\t\t\treturn new Problem(source);\n\t\t}\n\n\t\tpublic Problem[] newArray(int size) {\n\t\t\treturn new Problem[size];\n\t\t}\n\t};\n\tpublic Throwable e;\n\n\tpublic Problem(Throwable e) {\n\t\tthis.e = e;\n\t}\n\n\tprotected Problem(Parcel in) {\n\t\tthis.e = (Throwable) in.readSerializable();\n\t}\n\n\t@Override\n\tpublic int describeContents() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void writeToParcel(Parcel dest, int flags) {\n\t\tdest.writeSerializable(this.e);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/ReceiverInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.content.ComponentName;\nimport android.content.IntentFilter;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class ReceiverInfo implements Parcelable {\n\tpublic static final Creator<ReceiverInfo> CREATOR = new Creator<ReceiverInfo>() {\n\t\t@Override\n\t\tpublic ReceiverInfo createFromParcel(Parcel source) {\n\t\t\treturn new ReceiverInfo(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ReceiverInfo[] newArray(int size) {\n\t\t\treturn new ReceiverInfo[size];\n\t\t}\n\t};\n\tpublic ComponentName component;\n\tpublic IntentFilter[] filters;\n\tpublic String permission;\n\n\tpublic ReceiverInfo(ComponentName component, IntentFilter[] filters, String permission) {\n\t\tthis.component = component;\n\t\tthis.filters = filters;\n\t\tthis.permission = permission;\n\t}\n\n\tprotected ReceiverInfo(Parcel in) {\n\t\tthis.component = in.readParcelable(ComponentName.class.getClassLoader());\n\t\tthis.filters = in.createTypedArray(IntentFilter.CREATOR);\n\t\tthis.permission = in.readString();\n\t}\n\n\t@Override\n\tpublic int describeContents() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void writeToParcel(Parcel dest, int flags) {\n\t\tdest.writeParcelable(this.component, flags);\n\t\tdest.writeTypedArray(this.filters, flags);\n\t\tdest.writeString(this.permission);\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/StubActivityRecord.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\n\n/**\n * @author Lody\n */\n\npublic class StubActivityRecord  {\n        public Intent intent;\n        public ActivityInfo info;\n        public ComponentName caller;\n        public int userId;\n\n        public StubActivityRecord(Intent intent, ActivityInfo info, ComponentName caller, int userId) {\n            this.intent = intent;\n            this.info = info;\n            this.caller = caller;\n            this.userId = userId;\n        }\n\n        public StubActivityRecord(Intent stub) {\n            this.intent = stub.getParcelableExtra(\"_VA_|_intent_\");\n            this.info = stub.getParcelableExtra(\"_VA_|_info_\");\n            this.caller = stub.getParcelableExtra(\"_VA_|_caller_\");\n            this.userId = stub.getIntExtra(\"_VA_|_user_id_\", 0);\n        }\n\n    public void saveToIntent(Intent stub) {\n        stub.putExtra(\"_VA_|_intent_\", intent);\n        stub.putExtra(\"_VA_|_info_\", info);\n        stub.putExtra(\"_VA_|_caller_\", caller);\n        stub.putExtra(\"_VA_|_user_id_\", userId);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/SyncInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\nimport android.os.Parcelable.Creator;\n\n/**\n * Information about the sync operation that is currently underway.\n */\npublic class SyncInfo {\n\n    public final int authorityId;\n\n    /**\n     * The {@link Account} that is currently being synced.\n     */\n    public final Account account;\n\n    /**\n     * The authority of the provider that is currently being synced.\n     */\n    public final String authority;\n\n    /**\n     * The start time of the current sync operation in milliseconds since boot.\n     * This is represented in elapsed real time.\n     * See {@link android.os.SystemClock#elapsedRealtime()}.\n     */\n    public final long startTime;\n\n    public SyncInfo(int authorityId, Account account, String authority,\n                    long startTime) {\n        this.authorityId = authorityId;\n        this.account = account;\n        this.authority = authority;\n        this.startTime = startTime;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel parcel, int flags) {\n        parcel.writeInt(authorityId);\n        account.writeToParcel(parcel, 0);\n        parcel.writeString(authority);\n        parcel.writeLong(startTime);\n    }\n\n    SyncInfo(Parcel parcel) {\n        authorityId = parcel.readInt();\n        account = new Account(parcel);\n        authority = parcel.readString();\n        startTime = parcel.readLong();\n    }\n\n    public android.content.SyncInfo create() {\n        return mirror.android.content.SyncInfo.ctor.newInstance(authorityId, account, authority, startTime);\n    }\n\n    public static final Creator<SyncInfo> CREATOR = new Creator<SyncInfo>() {\n        public SyncInfo createFromParcel(Parcel in) {\n            return new SyncInfo(in);\n        }\n\n        public SyncInfo[] newArray(int size) {\n            return new SyncInfo[size];\n        }\n    };\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/VDeviceInfo.java",
    "content": "package com.lody.virtual.remote;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.os.VEnvironment;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\n\n/**\n * @author Lody\n */\npublic class VDeviceInfo implements Parcelable {\n\n    public String deviceId;\n    public String androidId;\n    public String wifiMac;\n    public String bluetoothMac;\n    public String iccId;\n    public String serial;\n    public String gmsAdId;\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.deviceId);\n        dest.writeString(this.androidId);\n        dest.writeString(this.wifiMac);\n        dest.writeString(this.bluetoothMac);\n        dest.writeString(this.iccId);\n        dest.writeString(this.serial);\n        dest.writeString(this.gmsAdId);\n    }\n\n    public VDeviceInfo() {}\n\n    public VDeviceInfo(Parcel in) {\n        this.deviceId = in.readString();\n        this.androidId = in.readString();\n        this.wifiMac = in.readString();\n        this.bluetoothMac = in.readString();\n        this.iccId = in.readString();\n        this.serial = in.readString();\n        this.gmsAdId = in.readString();\n    }\n\n    public static final Parcelable.Creator<VDeviceInfo> CREATOR = new Parcelable.Creator<VDeviceInfo>() {\n        @Override\n        public VDeviceInfo createFromParcel(Parcel source) {\n            return new VDeviceInfo(source);\n        }\n\n        @Override\n        public VDeviceInfo[] newArray(int size) {\n            return new VDeviceInfo[size];\n        }\n    };\n\n    public File getWifiFile(int userId) {\n        File wifiMacFie = VEnvironment.getWifiMacFile(userId);\n        if (!wifiMacFie.exists()) {\n            try {\n                RandomAccessFile file = new RandomAccessFile(wifiMacFie, \"rws\");\n                file.write((wifiMac + \"\\n\").getBytes());\n                file.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return wifiMacFie;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/VParceledListSlice.java",
    "content": "package com.lody.virtual.remote;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.util.Log;\n\n/**\n * Transfer a large list of Parcelable objects across an IPC. Splits into\n * multiple transactions if needed.\n *\n * Caveat: for efficiency and security, all elements must be the same concrete\n * type. In order to avoid writing the class name of each object, we must ensure\n * that each object is the same type, or else unparceling then reparceling the\n * data may yield a different result if the class name encoded in the Parcelable\n * is a Base type. See b/17671747.\n *\n * @hide\n *\n * \t\tOpenSilk: Modified to remove the creator optimization which uses hidden\n *       apis. this means we write an extra string for every list item. Class\n *       verification left in place since the Base type issue still applies\n */\npublic class VParceledListSlice<T extends Parcelable> implements Parcelable {\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static final Parcelable.ClassLoaderCreator<VParceledListSlice> CREATOR = new Parcelable.ClassLoaderCreator<VParceledListSlice>() {\n\t\tpublic VParceledListSlice createFromParcel(Parcel in) {\n\t\t\treturn new VParceledListSlice(in, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic VParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {\n\t\t\treturn new VParceledListSlice(in, loader);\n\t\t}\n\n\t\tpublic VParceledListSlice[] newArray(int size) {\n\t\t\treturn new VParceledListSlice[size];\n\t\t}\n\t};\n\t/*\n\t * TODO get this number from somewhere else. For now set it to a quarter of\n\t * the 1MB limit.\n\t */\n\tprivate static final int MAX_IPC_SIZE = 256 * 1024;\n\tprivate static final int MAX_FIRST_IPC_SIZE = MAX_IPC_SIZE / 2;\n\tprivate static String TAG = \"ParceledListSlice\";\n\tprivate static boolean DEBUG = false;\n\tprivate final List<T> mList;\n\n\tpublic VParceledListSlice(List<T> list) {\n\t\tmList = list;\n\t}\n\n\tprivate VParceledListSlice(Parcel p, ClassLoader loader) {\n\t\tfinal int N = p.readInt();\n\t\tmList = new ArrayList<T>(N);\n\t\tif (DEBUG)\n\t\t\tLog.d(TAG, \"Retrieving \" + N + \" items\");\n\t\tif (N <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Parcelable.Creator<T> creator = p.readParcelableCreator(loader);\n\t\tClass<?> listElementClass = null;\n\n\t\tint i = 0;\n\t\twhile (i < N) {\n\t\t\tif (p.readInt() == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// final T parcelable = p.readCreator(creator, loader);\n\t\t\tfinal T parcelable = p.readParcelable(loader);\n\t\t\tif (listElementClass == null) {\n\t\t\t\tlistElementClass = parcelable.getClass();\n\t\t\t} else {\n\t\t\t\tverifySameType(listElementClass, parcelable.getClass());\n\t\t\t}\n\n\t\t\tmList.add(parcelable);\n\n\t\t\tif (DEBUG)\n\t\t\t\tLog.d(TAG, \"Read inline #\" + i + \": \" + mList.get(mList.size() - 1));\n\t\t\ti++;\n\t\t}\n\t\tif (i >= N) {\n\t\t\treturn;\n\t\t}\n\t\tfinal IBinder retriever = p.readStrongBinder();\n\t\twhile (i < N) {\n\t\t\tif (DEBUG)\n\t\t\t\tLog.d(TAG, \"Reading more @\" + i + \" of \" + N + \": retriever=\" + retriever);\n\t\t\tParcel data = Parcel.obtain();\n\t\t\tParcel reply = Parcel.obtain();\n\t\t\tdata.writeInt(i);\n\t\t\ttry {\n\t\t\t\tretriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);\n\t\t\t} catch (RemoteException e) {\n\t\t\t\tLog.w(TAG, \"Failure retrieving array; only received \" + i + \" of \" + N, e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\twhile (i < N && reply.readInt() != 0) {\n\t\t\t\t// final T parcelable = reply.readCreator(creator, loader);\n\t\t\t\tfinal T parcelable = reply.readParcelable(loader);\n\t\t\t\tverifySameType(listElementClass, parcelable.getClass());\n\n\t\t\t\tmList.add(parcelable);\n\n\t\t\t\tif (DEBUG)\n\t\t\t\t\tLog.d(TAG, \"Read extra #\" + i + \": \" + mList.get(mList.size() - 1));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\treply.recycle();\n\t\t\tdata.recycle();\n\t\t}\n\t}\n\n\tprivate static void verifySameType(final Class<?> expected, final Class<?> actual) {\n\t\tif (!actual.equals(expected)) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Can't unparcel type \" + actual.getName() + \" in list of type \" + expected.getName());\n\t\t}\n\t}\n\n\tpublic List<T> getList() {\n\t\treturn mList;\n\t}\n\n\t@Override\n\tpublic int describeContents() {\n\t\tint contents = 0;\n\t\tfor (int i = 0; i < mList.size(); i++) {\n\t\t\tcontents |= mList.get(i).describeContents();\n\t\t}\n\t\treturn contents;\n\t}\n\n\t/**\n\t * Write this to another Parcel. Note that this discards the internal Parcel\n\t * and should not be used anymore. This is so we can pass this to a Binder\n\t * where we won't have a chance to call recycle on this.\n\t */\n\t@Override\n\tpublic void writeToParcel(Parcel dest, int flags) {\n\t\tfinal int N = mList.size();\n\t\tfinal int callFlags = flags;\n\t\tdest.writeInt(N);\n\t\tif (DEBUG)\n\t\t\tLog.d(TAG, \"Writing \" + N + \" items\");\n\t\tif (N > 0) {\n\t\t\tfinal Class<?> listElementClass = mList.get(0).getClass();\n\t\t\t// dest.writeParcelableCreator(mList.get(0));\n\t\t\tint i = 0;\n\t\t\twhile (i < N && dest.dataSize() < MAX_FIRST_IPC_SIZE) {\n\t\t\t\tdest.writeInt(1);\n\n\t\t\t\tfinal T parcelable = mList.get(i);\n\t\t\t\tverifySameType(listElementClass, parcelable.getClass());\n\t\t\t\t// parcelable.writeToParcel(dest, callFlags);\n\t\t\t\tdest.writeParcelable(parcelable, callFlags);\n\n\t\t\t\tif (DEBUG)\n\t\t\t\t\tLog.d(TAG, \"Wrote inline #\" + i + \": \" + mList.get(i));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < N) {\n\t\t\t\tdest.writeInt(0);\n\t\t\t\tBinder retriever = new Binder() {\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected boolean onTransact(int code, Parcel data, Parcel reply, int flags)\n\t\t\t\t\t\t\tthrows RemoteException {\n\t\t\t\t\t\tif (code != FIRST_CALL_TRANSACTION) {\n\t\t\t\t\t\t\treturn super.onTransact(code, data, reply, flags);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tint i = data.readInt();\n\t\t\t\t\t\tif (DEBUG)\n\t\t\t\t\t\t\tLog.d(TAG, \"Writing more @\" + i + \" of \" + N);\n\t\t\t\t\t\twhile (i < N && reply.dataSize() < MAX_IPC_SIZE) {\n\t\t\t\t\t\t\treply.writeInt(1);\n\n\t\t\t\t\t\t\tfinal T parcelable = mList.get(i);\n\t\t\t\t\t\t\tverifySameType(listElementClass, parcelable.getClass());\n\t\t\t\t\t\t\t// parcelable.writeToParcel(reply, callFlags);\n\t\t\t\t\t\t\treply.writeParcelable(parcelable, callFlags);\n\n\t\t\t\t\t\t\tif (DEBUG)\n\t\t\t\t\t\t\t\tLog.d(TAG, \"Wrote extra #\" + i + \": \" + mList.get(i));\n\t\t\t\t\t\t\ti++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (i < N) {\n\t\t\t\t\t\t\tif (DEBUG)\n\t\t\t\t\t\t\t\tLog.d(TAG, \"Breaking @\" + i + \" of \" + N);\n\t\t\t\t\t\t\treply.writeInt(0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tif (DEBUG)\n\t\t\t\t\tLog.d(TAG, \"Breaking @\" + i + \" of \" + N + \": retriever=\" + retriever);\n\t\t\t\tdest.writeStrongBinder(retriever);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/vloc/VCell.java",
    "content": "package com.lody.virtual.remote.vloc;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class VCell implements Parcelable {\n\n    public int type;\n    public int mcc;\n    public int mnc;\n    public int psc;\n    public int lac;\n    public int cid;\n    public int baseStationId;\n    public int systemId;\n    public int networkId;\n\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.type);\n        dest.writeInt(this.mcc);\n        dest.writeInt(this.mnc);\n        dest.writeInt(this.psc);\n        dest.writeInt(this.lac);\n        dest.writeInt(this.cid);\n        dest.writeInt(this.baseStationId);\n        dest.writeInt(this.systemId);\n        dest.writeInt(this.networkId);\n    }\n\n    public VCell() {\n    }\n\n    public VCell(Parcel in) {\n        this.type = in.readInt();\n        this.mcc = in.readInt();\n        this.mnc = in.readInt();\n        this.psc = in.readInt();\n        this.lac = in.readInt();\n        this.cid = in.readInt();\n        this.baseStationId = in.readInt();\n        this.systemId = in.readInt();\n        this.networkId = in.readInt();\n    }\n\n    public static final Parcelable.Creator<VCell> CREATOR = new Parcelable.Creator<VCell>() {\n        @Override\n        public VCell createFromParcel(Parcel source) {\n            return new VCell(source);\n        }\n\n        @Override\n        public VCell[] newArray(int size) {\n            return new VCell[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/vloc/VLocation.java",
    "content": "package com.lody.virtual.remote.vloc;\n\nimport android.location.Location;\nimport android.location.LocationManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.client.env.VirtualGPSSatalines;\nimport com.lody.virtual.helper.utils.Reflect;\n\n/**\n * @author Lody\n */\n\npublic class VLocation implements Parcelable {\n\n    public double latitude = 0.0;\n    public double longitude = 0.0;\n    public double altitude = 0.0f;\n    public float accuracy = 0.0f;\n    public float speed;\n    public float bearing;\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeDouble(latitude);\n        dest.writeDouble(longitude);\n        dest.writeDouble(altitude);\n        dest.writeFloat(accuracy);\n        dest.writeFloat(speed);\n        dest.writeFloat(bearing);\n    }\n\n    public VLocation() {\n    }\n\n    public VLocation(Parcel in) {\n        latitude = in.readDouble();\n        longitude = in.readDouble();\n        altitude = in.readDouble();\n        accuracy = in.readFloat();\n        speed = in.readFloat();\n        bearing = in.readFloat();\n    }\n\n    public boolean isEmpty() {\n        return latitude == 0 && longitude == 0;\n    }\n\n    public static final Parcelable.Creator<VLocation> CREATOR = new Parcelable.Creator<VLocation>() {\n        @Override\n        public VLocation createFromParcel(Parcel source) {\n            return new VLocation(source);\n        }\n\n        @Override\n        public VLocation[] newArray(int size) {\n            return new VLocation[size];\n        }\n    };\n\n    @Override\n    public String toString() {\n        return \"VLocation{\" +\n                \"latitude=\" + latitude +\n                \", longitude=\" + longitude +\n                \", altitude=\" + altitude +\n                \", accuracy=\" + accuracy +\n                \", speed=\" + speed +\n                \", bearing=\" + bearing +\n                '}';\n    }\n\n    public Location toSysLocation() {\n        Location location = new Location(LocationManager.GPS_PROVIDER);\n        location.setAccuracy(8f);\n        Bundle extraBundle = new Bundle();\n        location.setBearing(bearing);\n        Reflect.on(location).call(\"setIsFromMockProvider\", false);\n        location.setLatitude(latitude);\n        location.setLongitude(longitude);\n        location.setSpeed(speed);\n        location.setTime(System.currentTimeMillis());\n        location.setExtras(extraBundle);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            location.setElapsedRealtimeNanos(277000000);\n        }\n        int svCount = VirtualGPSSatalines.get().getSvCount();\n        extraBundle.putInt(\"satellites\", svCount);\n        extraBundle.putInt(\"satellitesvalue\", svCount);\n        return location;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/remote/vloc/VWifi.java",
    "content": "package com.lody.virtual.remote.vloc;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class VWifi implements Parcelable {\n\n    public String ssid;\n    public String bssid;\n    public String capabilities;\n    public int level;\n    public int frequency;\n    public long timestamp;\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.ssid);\n        dest.writeString(this.bssid);\n        dest.writeString(this.capabilities);\n        dest.writeInt(this.level);\n        dest.writeInt(this.frequency);\n        dest.writeLong(this.timestamp);\n    }\n\n    public VWifi() {\n    }\n\n    public VWifi(Parcel in) {\n        this.ssid = in.readString();\n        this.bssid = in.readString();\n        this.capabilities = in.readString();\n        this.level = in.readInt();\n        this.frequency = in.readInt();\n        this.timestamp = in.readLong();\n    }\n\n    public static final Parcelable.Creator<VWifi> CREATOR = new Parcelable.Creator<VWifi>() {\n        @Override\n        public VWifi createFromParcel(Parcel source) {\n            return new VWifi(source);\n        }\n\n        @Override\n        public VWifi[] newArray(int size) {\n            return new VWifi[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/BinderProvider.java",
    "content": "package com.lody.virtual.server;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.ServiceManagerNative;\nimport com.lody.virtual.client.stub.DaemonService;\nimport com.lody.virtual.helper.compat.BundleCompat;\nimport com.lody.virtual.server.accounts.VAccountManagerService;\nimport com.lody.virtual.server.am.BroadcastSystem;\nimport com.lody.virtual.server.am.VActivityManagerService;\nimport com.lody.virtual.server.device.VDeviceManagerService;\nimport com.lody.virtual.server.interfaces.IServiceFetcher;\nimport com.lody.virtual.server.job.VJobSchedulerService;\nimport com.lody.virtual.server.location.VirtualLocationService;\nimport com.lody.virtual.server.notification.VNotificationManagerService;\nimport com.lody.virtual.server.pm.VAppManagerService;\nimport com.lody.virtual.server.pm.VPackageManagerService;\nimport com.lody.virtual.server.pm.VUserManagerService;\nimport com.lody.virtual.server.vs.VirtualStorageService;\n\n/**\n * @author Lody\n */\npublic final class BinderProvider extends ContentProvider {\n\n    private final ServiceFetcher mServiceFetcher = new ServiceFetcher();\n\n    @Override\n    public boolean onCreate() {\n        Context context = getContext();\n        DaemonService.startup(context);\n        if (!VirtualCore.get().isStartup()) {\n            return true;\n        }\n        VPackageManagerService.systemReady();\n        addService(ServiceManagerNative.PACKAGE, VPackageManagerService.get());\n        VActivityManagerService.systemReady(context);\n        addService(ServiceManagerNative.ACTIVITY, VActivityManagerService.get());\n        addService(ServiceManagerNative.USER, VUserManagerService.get());\n        VAppManagerService.systemReady();\n        addService(ServiceManagerNative.APP, VAppManagerService.get());\n        BroadcastSystem.attach(VActivityManagerService.get(), VAppManagerService.get());\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            addService(ServiceManagerNative.JOB, VJobSchedulerService.get());\n        }\n        VNotificationManagerService.systemReady(context);\n        addService(ServiceManagerNative.NOTIFICATION, VNotificationManagerService.get());\n        VAppManagerService.get().scanApps();\n        VAccountManagerService.systemReady();\n        addService(ServiceManagerNative.ACCOUNT, VAccountManagerService.get());\n        addService(ServiceManagerNative.VS, VirtualStorageService.get());\n        addService(ServiceManagerNative.DEVICE, VDeviceManagerService.get());\n        addService(ServiceManagerNative.VIRTUAL_LOC, VirtualLocationService.get());\n        return true;\n    }\n\n\n    private void addService(String name, IBinder service) {\n        ServiceCache.addService(name, service);\n    }\n\n    @Override\n    public Bundle call(String method, String arg, Bundle extras) {\n        if (\"@\".equals(method)) {\n            Bundle bundle = new Bundle();\n            BundleCompat.putBinder(bundle, \"_VA_|_binder_\", mServiceFetcher);\n            return bundle;\n        }\n        return null;\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        return null;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return null;\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        return null;\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        return 0;\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        return 0;\n    }\n\n    private class ServiceFetcher extends IServiceFetcher.Stub {\n        @Override\n        public IBinder getService(String name) throws RemoteException {\n            if (name != null) {\n                return ServiceCache.getService(name);\n            }\n            return null;\n        }\n\n        @Override\n        public void addService(String name, IBinder service) throws RemoteException {\n            if (name != null && service != null) {\n                ServiceCache.addService(name, service);\n            }\n        }\n\n        @Override\n        public void removeService(String name) throws RemoteException {\n            if (name != null) {\n                ServiceCache.removeService(name);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/IJobScheduler.java",
    "content": "/*\n * This file is auto-generated.  DO NOT MODIFY.\n * Original file: /Users/weishu/dev/github/VirtualXposed/VirtualApp/lib/src/main/aidl/com/lody/virtual/server/IJobScheduler.aidl\n */\npackage com.lody.virtual.server;\n\nimport android.app.job.JobInfo;\nimport android.app.job.JobWorkItem;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport java.util.List;\n\n/**\n * IPC interface that supports the app-facing {@link android.app.job.JobScheduler} api.\n */\npublic interface IJobScheduler extends android.os.IInterface {\n    /**\n     * Local-side IPC implementation stub class.\n     */\n    public static abstract class Stub extends android.os.Binder implements com.lody.virtual.server.IJobScheduler {\n        private static final java.lang.String DESCRIPTOR = \"com.lody.virtual.server.IJobScheduler\";\n\n        /**\n         * Construct the stub at attach it to the interface.\n         */\n        public Stub() {\n            this.attachInterface(this, DESCRIPTOR);\n        }\n\n        /**\n         * Cast an IBinder object into an com.lody.virtual.server.IJobScheduler interface,\n         * generating a proxy if needed.\n         */\n        public static com.lody.virtual.server.IJobScheduler asInterface(android.os.IBinder obj) {\n            if ((obj == null)) {\n                return null;\n            }\n            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);\n            if (((iin != null) && (iin instanceof com.lody.virtual.server.IJobScheduler))) {\n                return ((com.lody.virtual.server.IJobScheduler) iin);\n            }\n            return new com.lody.virtual.server.IJobScheduler.Stub.Proxy(obj);\n        }\n\n        @Override\n        public android.os.IBinder asBinder() {\n            return this;\n        }\n\n        @Override\n        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n            switch (code) {\n                case INTERFACE_TRANSACTION: {\n                    reply.writeString(DESCRIPTOR);\n                    return true;\n                }\n                case TRANSACTION_schedule: {\n                    data.enforceInterface(DESCRIPTOR);\n                    JobInfo _arg0;\n                    if ((0 != data.readInt())) {\n                        _arg0 = JobInfo.CREATOR.createFromParcel(data);\n                    } else {\n                        _arg0 = null;\n                    }\n                    int _result = this.schedule(_arg0);\n                    reply.writeNoException();\n                    reply.writeInt(_result);\n                    return true;\n                }\n                case TRANSACTION_cancel: {\n                    data.enforceInterface(DESCRIPTOR);\n                    int _arg0;\n                    _arg0 = data.readInt();\n                    this.cancel(_arg0);\n                    reply.writeNoException();\n                    return true;\n                }\n                case TRANSACTION_cancelAll: {\n                    data.enforceInterface(DESCRIPTOR);\n                    this.cancelAll();\n                    reply.writeNoException();\n                    return true;\n                }\n                case TRANSACTION_getAllPendingJobs: {\n                    data.enforceInterface(DESCRIPTOR);\n                    List<JobInfo> _result = this.getAllPendingJobs();\n                    reply.writeNoException();\n                    reply.writeTypedList(_result);\n                    return true;\n                }\n                case TRANSACTION_enqueue: {\n                    data.enforceInterface(DESCRIPTOR);\n                    JobInfo _arg0;\n                    if ((0 != data.readInt())) {\n                        _arg0 = JobInfo.CREATOR.createFromParcel(data);\n                    } else {\n                        _arg0 = null;\n                    }\n                    JobWorkItem _arg1;\n                    if ((0 != data.readInt())) {\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                            _arg1 = JobWorkItem.CREATOR.createFromParcel(data);\n                        } else {\n                            _arg1 = null;\n                        }\n                    } else {\n                        _arg1 = null;\n                    }\n                    int _result = this.enqueue(_arg0, _arg1);\n                    reply.writeNoException();\n                    reply.writeInt(_result);\n                    return true;\n                }\n                case TRANSACTION_getPendingJob: {\n                    data.enforceInterface(DESCRIPTOR);\n                    int _arg0;\n                    _arg0 = data.readInt();\n                    JobInfo _result = this.getPendingJob(_arg0);\n                    reply.writeNoException();\n                    if ((_result != null)) {\n                        reply.writeInt(1);\n                        _result.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);\n                    } else {\n                        reply.writeInt(0);\n                    }\n                    return true;\n                }\n            }\n            return super.onTransact(code, data, reply, flags);\n        }\n\n        private static class Proxy implements com.lody.virtual.server.IJobScheduler {\n            private android.os.IBinder mRemote;\n\n            Proxy(android.os.IBinder remote) {\n                mRemote = remote;\n            }\n\n            @Override\n            public android.os.IBinder asBinder() {\n                return mRemote;\n            }\n\n            public java.lang.String getInterfaceDescriptor() {\n                return DESCRIPTOR;\n            }\n\n            @Override\n            public int schedule(android.app.job.JobInfo job) throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                int _result;\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    if ((job != null)) {\n                        _data.writeInt(1);\n                        job.writeToParcel(_data, 0);\n                    } else {\n                        _data.writeInt(0);\n                    }\n                    mRemote.transact(Stub.TRANSACTION_schedule, _data, _reply, 0);\n                    _reply.readException();\n                    _result = _reply.readInt();\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n                return _result;\n            }\n\n            @Override\n            public void cancel(int jobId) throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    _data.writeInt(jobId);\n                    mRemote.transact(Stub.TRANSACTION_cancel, _data, _reply, 0);\n                    _reply.readException();\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n            }\n\n            @Override\n            public void cancelAll() throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    mRemote.transact(Stub.TRANSACTION_cancelAll, _data, _reply, 0);\n                    _reply.readException();\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n            }\n\n            @Override\n            public java.util.List<android.app.job.JobInfo> getAllPendingJobs() throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                java.util.List<android.app.job.JobInfo> _result;\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    mRemote.transact(Stub.TRANSACTION_getAllPendingJobs, _data, _reply, 0);\n                    _reply.readException();\n                    _result = _reply.createTypedArrayList(android.app.job.JobInfo.CREATOR);\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n                return _result;\n            }\n\n            @Override\n            public int enqueue(android.app.job.JobInfo job, android.app.job.JobWorkItem work) throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                int _result;\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    if ((job != null)) {\n                        _data.writeInt(1);\n                        job.writeToParcel(_data, 0);\n                    } else {\n                        _data.writeInt(0);\n                    }\n                    if ((work != null)) {\n                        _data.writeInt(1);\n                        work.writeToParcel(_data, 0);\n                    } else {\n                        _data.writeInt(0);\n                    }\n                    mRemote.transact(Stub.TRANSACTION_enqueue, _data, _reply, 0);\n                    _reply.readException();\n                    _result = _reply.readInt();\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n                return _result;\n            }\n\n            @Override\n            public android.app.job.JobInfo getPendingJob(int i) throws android.os.RemoteException {\n                android.os.Parcel _data = android.os.Parcel.obtain();\n                android.os.Parcel _reply = android.os.Parcel.obtain();\n                android.app.job.JobInfo _result;\n                try {\n                    _data.writeInterfaceToken(DESCRIPTOR);\n                    _data.writeInt(i);\n                    mRemote.transact(Stub.TRANSACTION_getPendingJob, _data, _reply, 0);\n                    _reply.readException();\n                    if ((0 != _reply.readInt())) {\n                        _result = android.app.job.JobInfo.CREATOR.createFromParcel(_reply);\n                    } else {\n                        _result = null;\n                    }\n                } finally {\n                    _reply.recycle();\n                    _data.recycle();\n                }\n                return _result;\n            }\n        }\n\n        static final int TRANSACTION_schedule = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);\n        static final int TRANSACTION_cancel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);\n        static final int TRANSACTION_cancelAll = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);\n        static final int TRANSACTION_getAllPendingJobs = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);\n        static final int TRANSACTION_enqueue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);\n        static final int TRANSACTION_getPendingJob = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);\n    }\n\n    public int schedule(android.app.job.JobInfo job) throws android.os.RemoteException;\n\n    public void cancel(int jobId) throws android.os.RemoteException;\n\n    public void cancelAll() throws android.os.RemoteException;\n\n    public java.util.List<android.app.job.JobInfo> getAllPendingJobs() throws android.os.RemoteException;\n\n    public int enqueue(android.app.job.JobInfo job, android.app.job.JobWorkItem work) throws android.os.RemoteException;\n\n    public android.app.job.JobInfo getPendingJob(int i) throws android.os.RemoteException;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/ServiceCache.java",
    "content": "package com.lody.virtual.server;\n\nimport android.os.IBinder;\n\nimport com.lody.virtual.helper.collection.ArrayMap;\n\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class ServiceCache {\n\n\tprivate static final Map<String, IBinder> sCache = new ArrayMap<>(5);\n\n\tpublic static void addService(String name, IBinder service) {\n\t\tsCache.put(name, service);\n\t}\n\n\tpublic static IBinder removeService(String name) {\n\t\treturn sCache.remove(name);\n\t}\n\n\tpublic static IBinder getService(String name) {\n\t\treturn sCache.get(name);\n\t}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/RegisteredServicesParser.java",
    "content": "package com.lody.virtual.server.accounts;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.res.AssetManager;\nimport android.content.res.Resources;\nimport android.content.res.XmlResourceParser;\nimport android.os.Bundle;\n\nimport com.lody.virtual.server.pm.PackageCacheManager;\nimport com.lody.virtual.server.pm.PackageSetting;\n\npublic class RegisteredServicesParser {\n\n    public XmlResourceParser getParser(Context context, ServiceInfo serviceInfo, String name) {\n        Bundle meta = serviceInfo.metaData;\n        if (meta != null) {\n            int xmlId = meta.getInt(name);\n            if (xmlId != 0) {\n                try {\n                    return getResources(context, serviceInfo.applicationInfo).getXml(xmlId);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return null;\n    }\n\n    public Resources getResources(Context context, ApplicationInfo appInfo) throws Exception {\n        PackageSetting ps = PackageCacheManager.getSetting(appInfo.packageName);\n        if (ps != null) {\n            AssetManager assets = mirror.android.content.res.AssetManager.ctor.newInstance();\n            mirror.android.content.res.AssetManager.addAssetPath.call(assets, ps.apkPath);\n            Resources hostRes = context.getResources();\n            return new Resources(assets, hostRes.getDisplayMetrics(), hostRes.getConfiguration());\n        }\n        return null;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccount.java",
    "content": "package com.lody.virtual.server.accounts;\n\nimport android.accounts.Account;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class VAccount implements Parcelable {\n    public static final Parcelable.Creator<VAccount> CREATOR = new Parcelable.Creator<VAccount>() {\n        @Override\n        public VAccount createFromParcel(Parcel source) {\n            return new VAccount(source);\n        }\n\n        @Override\n        public VAccount[] newArray(int size) {\n            return new VAccount[size];\n        }\n    };\n    public int userId;\n    public String name;\n    public String previousName;\n    public String type;\n    public String password;\n    public long lastAuthenticatedTime;\n    public Map<String, String> authTokens;\n    public Map<String, String> userDatas;\n\n\n    public VAccount(int userId, Account account) {\n        this.userId = userId;\n        name = account.name;\n        type = account.type;\n        authTokens = new HashMap<>();\n        userDatas = new HashMap<>();\n    }\n\n    public VAccount(Parcel in) {\n        userId = in.readInt();\n        name = in.readString();\n        previousName = in.readString();\n        type = in.readString();\n        password = in.readString();\n        lastAuthenticatedTime = in.readLong();\n        int authTokensSize = in.readInt();\n        authTokens = new HashMap<>(authTokensSize);\n        for (int i = 0; i < authTokensSize; i++) {\n            String key = in.readString();\n            String value = in.readString();\n            authTokens.put(key, value);\n        }\n        int userDatasSize = in.readInt();\n        userDatas = new HashMap<>(userDatasSize);\n        for (int i = 0; i < userDatasSize; i++) {\n            String key = in.readString();\n            String value = in.readString();\n            userDatas.put(key, value);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(userId);\n        dest.writeString(name);\n        dest.writeString(previousName);\n        dest.writeString(type);\n        dest.writeString(password);\n        dest.writeLong(lastAuthenticatedTime);\n        dest.writeInt(authTokens.size());\n        for (Map.Entry<String, String> entry : authTokens.entrySet()) {\n            dest.writeString(entry.getKey());\n            dest.writeString(entry.getValue());\n        }\n        dest.writeInt(userDatas.size());\n        for (Map.Entry<String, String> entry : userDatas.entrySet()) {\n            dest.writeString(entry.getKey());\n            dest.writeString(entry.getValue());\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VAccountManagerService.java",
    "content": "package com.lody.virtual.server.accounts;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.accounts.AuthenticatorDescription;\nimport android.accounts.IAccountAuthenticator;\nimport android.accounts.IAccountAuthenticatorResponse;\nimport android.accounts.IAccountManagerResponse;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.content.res.XmlResourceParser;\nimport android.os.Binder;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.util.SparseArray;\nimport android.util.Xml;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.compat.AccountManagerCompat;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VBinder;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.server.IAccountManager;\nimport com.lody.virtual.server.am.VActivityManagerService;\nimport com.lody.virtual.server.pm.VPackageManagerService;\n\nimport org.xmlpull.v1.XmlPullParser;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport mirror.com.android.internal.R_Hide;\n\nimport static android.accounts.AccountManager.ERROR_CODE_BAD_ARGUMENTS;\n\n\n/**\n * @author Lody\n */\npublic class VAccountManagerService extends IAccountManager.Stub {\n\n    private static final AtomicReference<VAccountManagerService> sInstance = new AtomicReference<>();\n    private static final long CHECK_IN_TIME = 30 * 24 * 60 * 1000L;\n    private static final String TAG = VAccountManagerService.class.getSimpleName();\n    private final SparseArray<List<VAccount>> accountsByUserId = new SparseArray<>();\n    private final LinkedList<AuthTokenRecord> authTokenRecords = new LinkedList<>();\n    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<>();\n    private final AuthenticatorCache cache = new AuthenticatorCache();\n    private Context mContext = VirtualCore.get().getContext();\n    private long lastAccountChangeTime = 0;\n\n\n    public static VAccountManagerService get() {\n        return sInstance.get();\n    }\n\n    public static void systemReady() {\n        VAccountManagerService service = new VAccountManagerService();\n        service.readAllAccounts();\n        sInstance.set(service);\n    }\n\n\n    private static AuthenticatorDescription parseAuthenticatorDescription(Resources resources, String packageName,\n                                                                          AttributeSet attributeSet) {\n        TypedArray array = resources.obtainAttributes(attributeSet, R_Hide.styleable.AccountAuthenticator.get());\n        try {\n            String accountType = array.getString(R_Hide.styleable.AccountAuthenticator_accountType.get());\n            int label = array.getResourceId(R_Hide.styleable.AccountAuthenticator_label.get(), 0);\n            int icon = array.getResourceId(R_Hide.styleable.AccountAuthenticator_icon.get(), 0);\n            int smallIcon = array.getResourceId(R_Hide.styleable.AccountAuthenticator_smallIcon.get(), 0);\n            int accountPreferences = array.getResourceId(R_Hide.styleable.AccountAuthenticator_accountPreferences.get(), 0);\n            boolean customTokens = array.getBoolean(R_Hide.styleable.AccountAuthenticator_customTokens.get(), false);\n            if (TextUtils.isEmpty(accountType)) {\n                return null;\n            }\n            return new AuthenticatorDescription(accountType, packageName, label, icon, smallIcon, accountPreferences,\n                    customTokens);\n        } finally {\n            array.recycle();\n        }\n    }\n\n\n    @Override\n    public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {\n        synchronized (cache) {\n            AuthenticatorDescription[] descArray = new AuthenticatorDescription[cache.authenticators.size()];\n            int i = 0;\n            for (AuthenticatorInfo info : cache.authenticators.values()) {\n                descArray[i] = info.desc;\n                i++;\n            }\n            return descArray;\n        }\n    }\n\n    @Override\n    public void getAccountsByFeatures(int userId, IAccountManagerResponse response, String type, String[] features) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (type == null) throw new IllegalArgumentException(\"accountType is null\");\n        AuthenticatorInfo info = getAuthenticatorInfo(type);\n        if (info == null) {\n            Bundle bundle = new Bundle();\n            bundle.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);\n            try {\n                response.onResult(bundle);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n\n        if (features == null || features.length == 0) {\n            Bundle bundle = new Bundle();\n            bundle.putParcelableArray(AccountManager.KEY_ACCOUNTS, getAccounts(userId, type));\n            try {\n                response.onResult(bundle);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        } else {\n            new GetAccountsByTypeAndFeatureSession(response, userId, info, features).bind();\n        }\n    }\n\n    @Override\n    public final String getPreviousName(int userId, Account account) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        synchronized (accountsByUserId) {\n            String previousName = null;\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                previousName = vAccount.previousName;\n            }\n            return previousName;\n        }\n    }\n\n\n    @Override\n    public Account[] getAccounts(int userId, String type) {\n        List<Account> accountList = getAccountList(userId, type);\n        return accountList.toArray(new Account[accountList.size()]);\n    }\n\n\n    private List<Account> getAccountList(int userId, String type) {\n        synchronized (accountsByUserId) {\n            List<Account> accounts = new ArrayList<>();\n            List<VAccount> vAccounts = accountsByUserId.get(userId);\n            if (vAccounts != null) {\n                for (VAccount vAccount : vAccounts) {\n                    if (type == null || vAccount.type.equals(type)) {\n                        accounts.add(new Account(vAccount.name, vAccount.type));\n                    }\n                }\n            }\n            return accounts;\n        }\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        try {\n            return super.onTransact(code, data, reply, flags);\n        } catch (Throwable e) {\n            e.printStackTrace();\n            throw e;\n        }\n    }\n\n    @Override\n    public final void getAuthToken(final int userId, final IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, boolean expectActivityLaunch, final Bundle loginOptions) {\n        if (response == null) {\n            throw new IllegalArgumentException(\"response is null\");\n        }\n        try {\n            if (account == null) {\n                VLog.w(TAG, \"getAuthToken called with null account\");\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account is null\");\n                return;\n            }\n            if (authTokenType == null) {\n                VLog.w(TAG, \"getAuthToken called with null authTokenType\");\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"authTokenType is null\");\n                return;\n            }\n        } catch (RemoteException e) {\n            e.printStackTrace();\n            return;\n        }\n        AuthenticatorInfo info = getAuthenticatorInfo(account.type);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        // Get the calling package. We will use it for the purpose of caching.\n        final String callerPkg = loginOptions.getString(AccountManagerCompat.KEY_ANDROID_PACKAGE_NAME);\n        final boolean customTokens = info.desc.customTokens;\n\n        loginOptions.putInt(AccountManager.KEY_CALLER_UID, VBinder.getCallingUid());\n        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());\n        if (notifyOnAuthFailure) {\n            loginOptions.putBoolean(AccountManagerCompat.KEY_NOTIFY_ON_FAILURE, true);\n        }\n        if (!customTokens) {\n            VAccount vAccount;\n            synchronized (accountsByUserId) {\n                vAccount = getAccount(userId, account);\n            }\n            String authToken = vAccount != null ? vAccount.authTokens.get(authTokenType) : null;\n            if (authToken != null) {\n                Bundle result = new Bundle();\n                result.putString(AccountManager.KEY_AUTHTOKEN, authToken);\n                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\n                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);\n                onResult(response, result);\n                return;\n            }\n        }\n        if (customTokens) {\n            String authToken = getCustomAuthToken(userId, account, authTokenType, callerPkg);\n            if (authToken != null) {\n                Bundle result = new Bundle();\n                result.putString(AccountManager.KEY_AUTHTOKEN, authToken);\n                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\n                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);\n                onResult(response, result);\n                return;\n            }\n        }\n        new Session(response, userId, info, expectActivityLaunch, false, account.name) {\n\n            @Override\n            protected String toDebugString(long now) {\n                return super.toDebugString(now) + \", getAuthToken\"\n                        + \", \" + account\n                        + \", authTokenType \" + authTokenType\n                        + \", loginOptions \" + loginOptions\n                        + \", notifyOnAuthFailure \" + notifyOnAuthFailure;\n            }\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);\n            }\n\n            @Override\n            public void onResult(Bundle result) throws RemoteException {\n                if (result != null) {\n                    String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);\n                    if (authToken != null) {\n                        String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);\n                        String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);\n                        if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {\n                            onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,\n                                    \"the type and name should not be empty\");\n                            return;\n                        }\n                        if (!customTokens) {\n                            synchronized (accountsByUserId) {\n                                VAccount account = getAccount(userId, name, type);\n                                if (account == null) {\n                                    List<VAccount> accounts = accountsByUserId.get(userId);\n                                    if (accounts == null) {\n                                        accounts = new ArrayList<>();\n                                        accountsByUserId.put(userId, accounts);\n                                    }\n                                    account = new VAccount(userId, new Account(name, type));\n                                    accounts.add(account);\n                                    saveAllAccounts();\n                                }\n                            }\n                        }\n                        long expiryMillis = result.getLong(\n                                AccountManagerCompat.KEY_CUSTOM_TOKEN_EXPIRY, 0L);\n                        if (customTokens\n                                && expiryMillis > System.currentTimeMillis()) {\n                            AuthTokenRecord record = new AuthTokenRecord(userId, account, authTokenType, callerPkg, authToken, expiryMillis);\n                            synchronized (authTokenRecords) {\n                                authTokenRecords.remove(record);\n                                authTokenRecords.add(record);\n                            }\n                        }\n                    }\n                    Intent intent = result.getParcelable(AccountManager.KEY_INTENT);\n                    if (intent != null && notifyOnAuthFailure && !customTokens) {\n                        // TODO: send Signin error Notification\n                    }\n                }\n                super.onResult(result);\n            }\n        }.bind();\n    }\n\n\n    @Override\n    public void setPassword(int userId, Account account, String password) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        setPasswordInternal(userId, account, password);\n    }\n\n    private void setPasswordInternal(int userId, Account account, String password) {\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                vAccount.password = password;\n                vAccount.authTokens.clear();\n                saveAllAccounts();\n                synchronized (authTokenRecords) {\n                    Iterator<AuthTokenRecord> iterator = authTokenRecords.iterator();\n                    while (iterator.hasNext()) {\n                        AuthTokenRecord record = iterator.next();\n                        if (record.userId == userId && record.account.equals(account)) {\n                            iterator.remove();\n                        }\n                    }\n                }\n                sendAccountsChangedBroadcast(userId);\n            }\n        }\n    }\n\n    @Override\n    public void setAuthToken(int userId, Account account, String authTokenType, String authToken) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        if (authTokenType == null) throw new IllegalArgumentException(\"authTokenType is null\");\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                // FIXME: cancelNotification\n                vAccount.authTokens.put(authTokenType, authToken);\n                this.saveAllAccounts();\n            }\n        }\n    }\n\n\n    @Override\n    public void setUserData(int userId, Account account, String key, String value) {\n        if (key == null) throw new IllegalArgumentException(\"key is null\");\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        VAccount vAccount = getAccount(userId, account);\n        if (vAccount != null) {\n            synchronized (accountsByUserId) {\n                vAccount.userDatas.put(key, value);\n                saveAllAccounts();\n            }\n        }\n    }\n\n\n    @Override\n    public void hasFeatures(int userId, IAccountManagerResponse response,\n                            final Account account, final String[] features) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        if (features == null) throw new IllegalArgumentException(\"features is null\");\n        AuthenticatorInfo info = this.getAuthenticatorInfo(account.type);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, false, true, account.name) {\n\n            @Override\n            public void run() throws RemoteException {\n                try {\n                    mAuthenticator.hasFeatures(this, account, features);\n                } catch (RemoteException e) {\n                    onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, \"remote exception\");\n                }\n            }\n\n            @Override\n            public void onResult(Bundle result) throws RemoteException {\n                IAccountManagerResponse response = getResponseAndClose();\n                if (response != null) {\n                    try {\n                        if (result == null) {\n                            response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, \"null bundle\");\n                            return;\n                        }\n                        Log.v(TAG, getClass().getSimpleName() + \" calling onResult() on response \"\n                                + response);\n                        final Bundle newResult = new Bundle();\n                        newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,\n                                result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));\n                        response.onResult(newResult);\n                    } catch (RemoteException e) {\n                        // if the caller is dead then there is no one to care about remote exceptions\n                        Log.v(TAG, \"failure while notifying response\", e);\n                    }\n                }\n            }\n        }.bind();\n    }\n\n\n    @Override\n    public void updateCredentials(int userId, final IAccountManagerResponse response, final Account account,\n                                  final String authTokenType, final boolean expectActivityLaunch,\n                                  final Bundle loginOptions) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        if (authTokenType == null) throw new IllegalArgumentException(\"authTokenType is null\");\n        AuthenticatorInfo info = this.getAuthenticatorInfo(account.type);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, expectActivityLaunch, false, account.name) {\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);\n            }\n\n            @Override\n            protected String toDebugString(long now) {\n                if (loginOptions != null) loginOptions.keySet();\n                return super.toDebugString(now) + \", updateCredentials\"\n                        + \", \" + account\n                        + \", authTokenType \" + authTokenType\n                        + \", loginOptions \" + loginOptions;\n            }\n\n        }.bind();\n    }\n\n    @Override\n    public String getPassword(int userId, Account account) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                return vAccount.password;\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public String getUserData(int userId, Account account, String key) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        if (key == null) throw new IllegalArgumentException(\"key is null\");\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                return vAccount.userDatas.get(key);\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public void editProperties(int userId, IAccountManagerResponse response, final String accountType,\n                               final boolean expectActivityLaunch) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (accountType == null) throw new IllegalArgumentException(\"accountType is null\");\n        AuthenticatorInfo info = this.getAuthenticatorInfo(accountType);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, expectActivityLaunch, true, null) {\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.editProperties(this, mAuthenticatorInfo.desc.type);\n            }\n\n            @Override\n            protected String toDebugString(long now) {\n                return super.toDebugString(now) + \", editProperties\"\n                        + \", accountType \" + accountType;\n            }\n\n        }.bind();\n\n    }\n\n\n    @Override\n    public void getAuthTokenLabel(int userId, IAccountManagerResponse response, final String accountType,\n                                  final String authTokenType) {\n        if (accountType == null) throw new IllegalArgumentException(\"accountType is null\");\n        if (authTokenType == null) throw new IllegalArgumentException(\"authTokenType is null\");\n        AuthenticatorInfo info = getAuthenticatorInfo(accountType);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, false, false, null) {\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.getAuthTokenLabel(this, authTokenType);\n            }\n\n            @Override\n            public void onResult(Bundle result) throws RemoteException {\n                if (result != null) {\n                    String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);\n                    Bundle bundle = new Bundle();\n                    bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);\n                    super.onResult(bundle);\n                } else {\n                    super.onResult(null);\n                }\n            }\n        }.bind();\n    }\n\n    public void confirmCredentials(int userId, IAccountManagerResponse response, final Account account, final Bundle options, final boolean expectActivityLaunch) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        AuthenticatorInfo info = getAuthenticatorInfo(account.type);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, expectActivityLaunch, true, account.name, true, true) {\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.confirmCredentials(this, account, options);\n            }\n\n        }.bind();\n\n    }\n\n    @Override\n    public void addAccount(int userId, final IAccountManagerResponse response, final String accountType,\n                           final String authTokenType, final String[] requiredFeatures,\n                           final boolean expectActivityLaunch, final Bundle optionsIn) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (accountType == null) throw new IllegalArgumentException(\"accountType is null\");\n        AuthenticatorInfo info = getAuthenticatorInfo(accountType);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        new Session(response, userId, info, expectActivityLaunch, true, null, false, true) {\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.addAccount(this, mAuthenticatorInfo.desc.type, authTokenType, requiredFeatures,\n                        optionsIn);\n            }\n\n            @Override\n            protected String toDebugString(long now) {\n                return super.toDebugString(now) + \", addAccount\"\n                        + \", accountType \" + accountType\n                        + \", requiredFeatures \"\n                        + (requiredFeatures != null\n                        ? TextUtils.join(\",\", requiredFeatures)\n                        : null);\n            }\n\n        }.bind();\n\n    }\n\n    @Override\n    public boolean addAccountExplicitly(int userId, Account account, String password, Bundle extras) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        return insertAccountIntoDatabase(userId, account, password, extras);\n    }\n\n    @Override\n    public boolean removeAccountExplicitly(int userId, Account account) {\n        return account != null && removeAccountInternal(userId, account);\n    }\n\n    @Override\n    public void renameAccount(int userId, IAccountManagerResponse response, Account accountToRename, String newName) {\n        if (accountToRename == null) throw new IllegalArgumentException(\"account is null\");\n        Account resultingAccount = renameAccountInternal(userId, accountToRename, newName);\n        Bundle result = new Bundle();\n        result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);\n        result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);\n        try {\n            response.onResult(result);\n        } catch (RemoteException e) {\n            Log.w(TAG, e.getMessage());\n        }\n    }\n\n    @Override\n    public void removeAccount(final int userId, IAccountManagerResponse response, final Account account,\n                              boolean expectActivityLaunch) {\n        if (response == null) throw new IllegalArgumentException(\"response is null\");\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        AuthenticatorInfo info = this.getAuthenticatorInfo(account.type);\n        if (info == null) {\n            try {\n                response.onError(ERROR_CODE_BAD_ARGUMENTS, \"account.type does not exist\");\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            return;\n        }\n        // FIXME: Cancel Notification\n\n        new Session(response, userId, info, expectActivityLaunch, true, account.name) {\n            @Override\n            protected String toDebugString(long now) {\n                return super.toDebugString(now) + \", removeAccount\"\n                        + \", account \" + account;\n            }\n\n            @Override\n            public void run() throws RemoteException {\n                mAuthenticator.getAccountRemovalAllowed(this, account);\n            }\n\n            @Override\n            public void onResult(Bundle result) throws RemoteException {\n                if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)\n                        && !result.containsKey(AccountManager.KEY_INTENT)) {\n                    final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);\n                    if (removalAllowed) {\n                        removeAccountInternal(userId, account);\n                    }\n                    IAccountManagerResponse response = getResponseAndClose();\n                    if (response != null) {\n                        Log.v(TAG, getClass().getSimpleName() + \" calling onResult() on response \"\n                                + response);\n                        Bundle result2 = new Bundle();\n                        result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);\n                        try {\n                            response.onResult(result2);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n                super.onResult(result);\n            }\n\n        }.bind();\n\n    }\n\n    @Override\n    public void clearPassword(int userId, Account account) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        setPasswordInternal(userId, account, null);\n    }\n\n    private boolean removeAccountInternal(int userId, Account account) {\n        List<VAccount> accounts = accountsByUserId.get(userId);\n        if (accounts != null) {\n            Iterator<VAccount> iterator = accounts.iterator();\n            while (iterator.hasNext()) {\n                VAccount vAccount = iterator.next();\n                if (userId == vAccount.userId\n                        && TextUtils.equals(vAccount.name, account.name)\n                        && TextUtils.equals(account.type, vAccount.type)) {\n                    iterator.remove();\n                    saveAllAccounts();\n                    sendAccountsChangedBroadcast(userId);\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n\n    @Override\n    public boolean accountAuthenticated(int userId, final Account account) {\n        if (account == null) {\n            throw new IllegalArgumentException(\"account is null\");\n        }\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                vAccount.lastAuthenticatedTime = System.currentTimeMillis();\n                saveAllAccounts();\n                return true;\n            }\n            return false;\n        }\n    }\n\n    @Override\n    public void invalidateAuthToken(int userId, String accountType, String authToken) {\n        if (accountType == null) throw new IllegalArgumentException(\"accountType is null\");\n        if (authToken == null) throw new IllegalArgumentException(\"authToken is null\");\n        synchronized (accountsByUserId) {\n            List<VAccount> accounts = accountsByUserId.get(userId);\n            if (accounts != null) {\n                boolean changed = false;\n                for (VAccount account : accounts) {\n                    if (account.type.equals(accountType)) {\n                        account.authTokens.values().remove(authToken);\n                        changed = true;\n                    }\n                }\n                if (changed) {\n                    saveAllAccounts();\n                }\n            }\n            synchronized (authTokenRecords) {\n                Iterator<AuthTokenRecord> iterator = authTokenRecords.iterator();\n                while (iterator.hasNext()) {\n                    AuthTokenRecord record = iterator.next();\n                    if (record.userId == userId && record.authTokenType.equals(accountType)\n                            && record.authToken.equals(authToken)) {\n                        iterator.remove();\n                    }\n                }\n            }\n        }\n    }\n\n\n    private Account renameAccountInternal(int userId, Account accountToRename, String newName) {\n        // TODO: Cancel Notification\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, accountToRename);\n            if (vAccount != null) {\n                vAccount.previousName = vAccount.name;\n                vAccount.name = newName;\n                saveAllAccounts();\n                Account newAccount = new Account(vAccount.name, vAccount.type);\n                synchronized (authTokenRecords) {\n                    for (AuthTokenRecord record : authTokenRecords) {\n                        if (record.userId == userId && record.account.equals(accountToRename)) {\n                            record.account = newAccount;\n                        }\n                    }\n                }\n                sendAccountsChangedBroadcast(userId);\n                return newAccount;\n            }\n        }\n        return accountToRename;\n    }\n\n    @Override\n    public String peekAuthToken(int userId, Account account, String authTokenType) {\n        if (account == null) throw new IllegalArgumentException(\"account is null\");\n        if (authTokenType == null) throw new IllegalArgumentException(\"authTokenType is null\");\n        synchronized (accountsByUserId) {\n            VAccount vAccount = getAccount(userId, account);\n            if (vAccount != null) {\n                return vAccount.authTokens.get(authTokenType);\n            }\n            return null;\n        }\n    }\n\n\n    private String getCustomAuthToken(int userId, Account account, String authTokenType, String packageName) {\n        AuthTokenRecord record = new AuthTokenRecord(userId, account, authTokenType, packageName);\n        String authToken = null;\n        long now = System.currentTimeMillis();\n        synchronized (authTokenRecords) {\n            Iterator<AuthTokenRecord> iterator = authTokenRecords.iterator();\n            while (iterator.hasNext()) {\n                AuthTokenRecord one = iterator.next();\n                if (one.expiryEpochMillis > 0 && one.expiryEpochMillis < now) {\n                    iterator.remove();\n                } else if (record.equals(one)) {\n                    authToken = record.authToken;\n                }\n            }\n        }\n        return authToken;\n    }\n\n    private void onResult(IAccountManagerResponse response, Bundle result) {\n        try {\n            response.onResult(result);\n        } catch (RemoteException e) {\n            // if the caller is dead then there is no one to care about remote\n            // exceptions\n            e.printStackTrace();\n        }\n    }\n\n    private AuthenticatorInfo getAuthenticatorInfo(String type) {\n        synchronized (cache) {\n            return type == null ? null : cache.authenticators.get(type);\n        }\n    }\n\n\n    private VAccount getAccount(int userId, Account account) {\n        return this.getAccount(userId, account.name, account.type);\n    }\n\n    private boolean insertAccountIntoDatabase(int userId, Account account, String password, Bundle extras) {\n        if (account == null) {\n            return false;\n        }\n        synchronized (accountsByUserId) {\n            VAccount vAccount = new VAccount(userId, account);\n            vAccount.password = password;\n            // convert the [Bundle] to [Map<String, String>]\n            if (extras != null) {\n                for (String key : extras.keySet()) {\n                    Object value = extras.get(key);\n                    if (value instanceof String) {\n                        vAccount.userDatas.put(key, (String) value);\n                    }\n                }\n            }\n            List<VAccount> accounts = accountsByUserId.get(userId);\n            if (accounts == null) {\n                accounts = new ArrayList<>();\n                accountsByUserId.put(userId, accounts);\n            }\n            accounts.add(vAccount);\n            saveAllAccounts();\n            sendAccountsChangedBroadcast(vAccount.userId);\n            return true;\n        }\n    }\n\n    private void sendAccountsChangedBroadcast(int userId) {\n        Intent intent = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);\n        VActivityManagerService.get().sendBroadcastAsUser(intent, new VUserHandle(userId));\n        broadcastCheckInNowIfNeed(userId);\n    }\n\n    private void broadcastCheckInNowIfNeed(int userId) {\n        long time = System.currentTimeMillis();\n        if (Math.abs(time - lastAccountChangeTime) > CHECK_IN_TIME) {\n            lastAccountChangeTime = time;\n            saveAllAccounts();\n            Intent intent = new Intent(\"android.server.checkin.CHECKIN_NOW\");\n            VActivityManagerService.get().sendBroadcastAsUser(intent, new VUserHandle(userId));\n        }\n    }\n\n    /**\n     * Serializing all accounts\n     */\n    private void saveAllAccounts() {\n        File accountFile = VEnvironment.getAccountConfigFile();\n        Parcel dest = Parcel.obtain();\n        try {\n            dest.writeInt(1);\n            List<VAccount> accounts = new ArrayList<>();\n            for (int i = 0; i < this.accountsByUserId.size(); i++) {\n                List<VAccount> list = this.accountsByUserId.valueAt(i);\n                if (list != null) {\n                    accounts.addAll(list);\n                }\n            }\n            dest.writeInt(accounts.size());\n            for (VAccount account : accounts) {\n                account.writeToParcel(dest, 0);\n            }\n            dest.writeLong(lastAccountChangeTime);\n            FileOutputStream fileOutputStream = new FileOutputStream(accountFile);\n            fileOutputStream.write(dest.marshall());\n            fileOutputStream.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        dest.recycle();\n    }\n\n    /**\n     * Read all accounts from file.\n     */\n    private void readAllAccounts() {\n        File accountFile = VEnvironment.getAccountConfigFile();\n        refreshAuthenticatorCache(null);\n        if (accountFile.exists()) {\n            accountsByUserId.clear();\n            Parcel dest = Parcel.obtain();\n            try {\n                FileInputStream is = new FileInputStream(accountFile);\n                byte[] bytes = new byte[(int) accountFile.length()];\n                int readLength = is.read(bytes);\n                is.close();\n                if (readLength != bytes.length) {\n                    throw new IOException(String.format(Locale.ENGLISH, \"Expect length %d, but got %d.\", bytes.length, readLength));\n                }\n                dest.unmarshall(bytes, 0, bytes.length);\n                dest.setDataPosition(0);\n                dest.readInt(); // skip the magic\n                int size = dest.readInt(); // the VAccount's size we need to read\n                boolean invalid = false;\n                while (size-- > 0) {\n                    VAccount account = new VAccount(dest);\n                    VLog.d(TAG, \"Reading account : \" + account.type);\n                    AuthenticatorInfo info = cache.authenticators.get(account.type);\n                    if (info != null) {\n                        List<VAccount> accounts = accountsByUserId.get(account.userId);\n                        if (accounts == null) {\n                            accounts = new ArrayList<>();\n                            accountsByUserId.put(account.userId, accounts);\n                        }\n                        accounts.add(account);\n                    } else {\n                        invalid = true;\n                    }\n                }\n                lastAccountChangeTime = dest.readLong();\n                if (invalid) {\n                    saveAllAccounts();\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            } finally {\n                dest.recycle();\n            }\n        }\n    }\n\n\n    private VAccount getAccount(int userId, String accountName, String accountType) {\n        List<VAccount> accounts = accountsByUserId.get(userId);\n        if (accounts != null) {\n            for (VAccount account : accounts) {\n                if (TextUtils.equals(account.name, accountName) && TextUtils.equals(account.type, accountType)) {\n                    return account;\n                }\n            }\n        }\n        return null;\n    }\n\n\n    public void refreshAuthenticatorCache(String packageName) {\n        cache.authenticators.clear();\n        Intent intent = new Intent(AccountManager.ACTION_AUTHENTICATOR_INTENT);\n        if (packageName != null) {\n            intent.setPackage(packageName);\n        }\n        generateServicesMap(\n                VPackageManagerService.get().queryIntentServices(intent, null, PackageManager.GET_META_DATA, 0),\n                cache.authenticators, new RegisteredServicesParser());\n    }\n\n    private void generateServicesMap(List<ResolveInfo> services, Map<String, AuthenticatorInfo> map,\n                                     RegisteredServicesParser accountParser) {\n        for (ResolveInfo info : services) {\n            XmlResourceParser parser = accountParser.getParser(mContext, info.serviceInfo,\n                    AccountManager.AUTHENTICATOR_META_DATA_NAME);\n            if (parser != null) {\n                try {\n                    AttributeSet attributeSet = Xml.asAttributeSet(parser);\n                    int type;\n                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {\n                        // Nothing to do\n                    }\n                    if (AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME.equals(parser.getName())) {\n                        AuthenticatorDescription desc = parseAuthenticatorDescription(\n                                accountParser.getResources(mContext, info.serviceInfo.applicationInfo),\n                                info.serviceInfo.packageName, attributeSet);\n                        if (desc != null) {\n                            map.put(desc.type, new AuthenticatorInfo(desc, info.serviceInfo));\n                        }\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    final static class AuthTokenRecord {\n        public int userId;\n        public Account account;\n        public long expiryEpochMillis;\n        public String authToken;\n        private String authTokenType;\n        private String packageName;\n\n        AuthTokenRecord(int userId, Account account, String authTokenType, String packageName, String authToken,\n                        long expiryEpochMillis) {\n            this.userId = userId;\n            this.account = account;\n            this.authTokenType = authTokenType;\n            this.packageName = packageName;\n            this.authToken = authToken;\n            this.expiryEpochMillis = expiryEpochMillis;\n        }\n\n        AuthTokenRecord(int userId, Account account, String authTokenType, String packageName) {\n            this.userId = userId;\n            this.account = account;\n            this.authTokenType = authTokenType;\n            this.packageName = packageName;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n            AuthTokenRecord that = (AuthTokenRecord) o;\n            return userId == that.userId\n                    && account.equals(that.account)\n                    && authTokenType.equals(that.authTokenType)\n                    && packageName.equals(that.packageName);\n        }\n\n        @Override\n        public int hashCode() {\n            return ((this.userId * 31 + this.account.hashCode()) * 31\n                    + this.authTokenType.hashCode()) * 31\n                    + this.packageName.hashCode();\n        }\n    }\n\n    private final class AuthenticatorInfo {\n        final AuthenticatorDescription desc;\n        final ServiceInfo serviceInfo;\n\n        AuthenticatorInfo(AuthenticatorDescription desc, ServiceInfo info) {\n            this.desc = desc;\n            this.serviceInfo = info;\n        }\n    }\n\n    private final class AuthenticatorCache {\n        final Map<String, AuthenticatorInfo> authenticators = new HashMap<>();\n    }\n\n    private abstract class Session extends IAccountAuthenticatorResponse.Stub\n            implements IBinder.DeathRecipient, ServiceConnection {\n        final int mUserId;\n        final AuthenticatorInfo mAuthenticatorInfo;\n        private final boolean mStripAuthTokenFromResult;\n        public int mNumResults;\n        IAccountAuthenticator mAuthenticator;\n        private IAccountManagerResponse mResponse;\n        private boolean mExpectActivityLaunch;\n        private long mCreationTime;\n        private String mAccountName;\n        private boolean mAuthDetailsRequired;\n        private boolean mUpdateLastAuthenticatedTime;\n        private int mNumRequestContinued;\n        private int mNumErrors;\n\n\n        Session(IAccountManagerResponse response, int userId, AuthenticatorInfo info, boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {\n            if (info == null) throw new IllegalArgumentException(\"accountType is null\");\n            this.mStripAuthTokenFromResult = stripAuthTokenFromResult;\n            this.mResponse = response;\n            this.mUserId = userId;\n            this.mAuthenticatorInfo = info;\n            this.mExpectActivityLaunch = expectActivityLaunch;\n            this.mCreationTime = SystemClock.elapsedRealtime();\n            this.mAccountName = accountName;\n            this.mAuthDetailsRequired = authDetailsRequired;\n            this.mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime;\n            synchronized (mSessions) {\n                mSessions.put(toString(), this);\n            }\n            if (response != null) {\n                try {\n                    response.asBinder().linkToDeath(this, 0 /* flags */);\n                } catch (RemoteException e) {\n                    mResponse = null;\n                    binderDied();\n                }\n            }\n        }\n\n        Session(IAccountManagerResponse response, int userId, AuthenticatorInfo info, boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName) {\n            this(response, userId, info, expectActivityLaunch, stripAuthTokenFromResult, accountName, false, false);\n        }\n\n        IAccountManagerResponse getResponseAndClose() {\n            if (mResponse == null) {\n                // this session has already been closed\n                return null;\n            }\n            IAccountManagerResponse response = mResponse;\n            close(); // this clears mResponse so we need to save the response before this call\n            return response;\n        }\n\n        private void close() {\n            synchronized (mSessions) {\n                if (mSessions.remove(toString()) == null) {\n                    // the session was already closed, so bail out now\n                    return;\n                }\n            }\n            if (mResponse != null) {\n                // stop listening for response deaths\n                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);\n\n                // clear this so that we don't accidentally send any further results\n                mResponse = null;\n            }\n            unbind();\n        }\n\n        @Override\n        public void onServiceConnected(ComponentName name, IBinder service) {\n            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);\n            try {\n                run();\n            } catch (RemoteException e) {\n                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,\n                        \"remote exception\");\n            }\n        }\n\n        @Override\n        public void onRequestContinued() {\n            mNumRequestContinued++;\n        }\n\n        @Override\n        public void onError(int errorCode, String errorMessage) {\n            mNumErrors++;\n            IAccountManagerResponse response = getResponseAndClose();\n            if (response != null) {\n                Log.v(TAG, getClass().getSimpleName()\n                        + \" calling onError() on response \" + response);\n                try {\n                    response.onError(errorCode, errorMessage);\n                } catch (RemoteException e) {\n                    Log.v(TAG, \"Session.onError: caught RemoteException while responding\", e);\n                }\n            } else {\n                Log.v(TAG, \"Session.onError: already closed\");\n            }\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName name) {\n            mAuthenticator = null;\n            IAccountManagerResponse response = getResponseAndClose();\n            if (response != null) {\n                try {\n                    response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,\n                            \"disconnected\");\n                } catch (RemoteException e) {\n                    Log.v(TAG, \"Session.onServiceDisconnected: \"\n                            + \"caught RemoteException while responding\", e);\n                }\n            }\n        }\n\n        @Override\n        public void onResult(Bundle result) throws RemoteException {\n            mNumResults++;\n            if (result != null) {\n                boolean isSuccessfulConfirmCreds = result.getBoolean(\n                        AccountManager.KEY_BOOLEAN_RESULT, false);\n                boolean isSuccessfulUpdateCredsOrAddAccount =\n                        result.containsKey(AccountManager.KEY_ACCOUNT_NAME)\n                                && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);\n                // We should only update lastAuthenticated time, if\n                // mUpdateLastAuthenticatedTime is true and the confirmRequest\n                // or updateRequest was successful\n                boolean needUpdate = mUpdateLastAuthenticatedTime\n                        && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);\n                if (needUpdate || mAuthDetailsRequired) {\n                    synchronized (accountsByUserId) {\n                        VAccount account = getAccount(mUserId, mAccountName, mAuthenticatorInfo.desc.type);\n                        if (needUpdate && account != null) {\n                            account.lastAuthenticatedTime = System.currentTimeMillis();\n                            saveAllAccounts();\n                        }\n                        if (mAuthDetailsRequired) {\n                            long lastAuthenticatedTime = -1;\n                            if (account != null) {\n                                lastAuthenticatedTime = account.lastAuthenticatedTime;\n                            }\n                            result.putLong(AccountManagerCompat.KEY_LAST_AUTHENTICATED_TIME, lastAuthenticatedTime);\n                        }\n                    }\n                }\n            }\n            if (result != null\n                    && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {\n//\t\t\t\tString accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);\n//\t\t\t\tString accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);\n//\t\t\t\tif (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {\n//\t\t\t\t\tAccount account = new Account(accountName, accountType);\n//\t\t\t\t\tFIXME: Cancel Notification\n//\t\t\t\t}\n            }\n            Intent intent = null;\n            if (result != null) {\n                intent = result.getParcelable(AccountManager.KEY_INTENT);\n            }\n            IAccountManagerResponse response;\n            if (mExpectActivityLaunch && result != null\n                    && result.containsKey(AccountManager.KEY_INTENT)) {\n                response = mResponse;\n            } else {\n                response = getResponseAndClose();\n            }\n            if (response != null) {\n                try {\n                    if (result == null) {\n                        Log.v(TAG, getClass().getSimpleName()\n                                + \" calling onError() on response \" + response);\n                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,\n                                \"null bundle returned\");\n                    } else {\n                        if (mStripAuthTokenFromResult) {\n                            result.remove(AccountManager.KEY_AUTHTOKEN);\n                        }\n                        Log.v(TAG, getClass().getSimpleName()\n                                + \" calling onResult() on response \" + response);\n                        if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&\n                                (intent == null)) {\n                            // All AccountManager error codes are greater than 0\n                            response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),\n                                    result.getString(AccountManager.KEY_ERROR_MESSAGE));\n                        } else {\n                            response.onResult(result);\n                        }\n                    }\n                } catch (RemoteException e) {\n                    // if the caller is dead then there is no one to care about remote exceptions\n                    Log.v(TAG, \"failure while notifying response\", e);\n                }\n            }\n        }\n\n        public abstract void run() throws RemoteException;\n\n        void bind() {\n            Log.v(TAG, \"initiating bind to authenticator type \" + mAuthenticatorInfo.desc.type);\n            Intent intent = new Intent();\n            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);\n            intent.setClassName(mAuthenticatorInfo.serviceInfo.packageName, mAuthenticatorInfo.serviceInfo.name);\n            intent.putExtra(\"_VA_|_user_id_\", mUserId);\n\n            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {\n                Log.d(TAG, \"bind attempt failed for \" + toDebugString());\n                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, \"bind failure\");\n            }\n        }\n\n        protected String toDebugString() {\n            return toDebugString(SystemClock.elapsedRealtime());\n        }\n\n        protected String toDebugString(long now) {\n            return \"Session: expectLaunch \" + mExpectActivityLaunch\n                    + \", connected \" + (mAuthenticator != null)\n                    + \", stats (\" + mNumResults + \"/\" + mNumRequestContinued\n                    + \"/\" + mNumErrors + \")\"\n                    + \", lifetime \" + ((now - mCreationTime) / 1000.0);\n        }\n\n        private void unbind() {\n            if (mAuthenticator != null) {\n                mAuthenticator = null;\n                mContext.unbindService(this);\n            }\n        }\n\n        @Override\n        public void binderDied() {\n            mResponse = null;\n            close();\n        }\n    }\n\n    private class GetAccountsByTypeAndFeatureSession extends Session {\n        private final String[] mFeatures;\n        private volatile Account[] mAccountsOfType = null;\n        private volatile ArrayList<Account> mAccountsWithFeatures = null;\n        private volatile int mCurrentAccount = 0;\n\n        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response, int userId, AuthenticatorInfo info, String[] features) {\n            super(response, userId, info, false /* expectActivityLaunch */,\n                    true /* stripAuthTokenFromResult */, null /* accountName */);\n            mFeatures = features;\n        }\n\n        @Override\n        public void run() throws RemoteException {\n            mAccountsOfType = getAccounts(mUserId, mAuthenticatorInfo.desc.type);\n            // check whether each account matches the requested features\n            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);\n            mCurrentAccount = 0;\n\n            checkAccount();\n        }\n\n        public void checkAccount() {\n            if (mCurrentAccount >= mAccountsOfType.length) {\n                sendResult();\n                return;\n            }\n\n            final IAccountAuthenticator accountAuthenticator = mAuthenticator;\n            if (accountAuthenticator == null) {\n                // It is possible that the authenticator has died, which is indicated by\n                // mAuthenticator being set to null. If this happens then just abort.\n                // There is no need to send back a result or error in this case since\n                // that already happened when mAuthenticator was cleared.\n                Log.v(TAG, \"checkAccount: aborting session since we are no longer\"\n                        + \" connected to the authenticator, \" + toDebugString());\n                return;\n            }\n            try {\n                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);\n            } catch (RemoteException e) {\n                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, \"remote exception\");\n            }\n        }\n\n        @Override\n        public void onResult(Bundle result) {\n            mNumResults++;\n            if (result == null) {\n                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, \"null bundle\");\n                return;\n            }\n            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {\n                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);\n            }\n            mCurrentAccount++;\n            checkAccount();\n        }\n\n        public void sendResult() {\n            IAccountManagerResponse response = getResponseAndClose();\n            if (response != null) {\n                try {\n                    Account[] accounts = new Account[mAccountsWithFeatures.size()];\n                    for (int i = 0; i < accounts.length; i++) {\n                        accounts[i] = mAccountsWithFeatures.get(i);\n                    }\n                    if (Log.isLoggable(TAG, Log.VERBOSE)) {\n                        Log.v(TAG, getClass().getSimpleName() + \" calling onResult() on response \"\n                                + response);\n                    }\n                    Bundle result = new Bundle();\n                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);\n                    response.onResult(result);\n                } catch (RemoteException e) {\n                    // if the caller is dead then there is no one to care about remote exceptions\n                    Log.v(TAG, \"failure while notifying response\", e);\n                }\n            }\n        }\n\n\n        @Override\n        protected String toDebugString(long now) {\n            return super.toDebugString(now) + \", getAccountsByTypeAndFeatures\"\n                    + \", \" + (mFeatures != null ? TextUtils.join(\",\", mFeatures) : null);\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VContentService.java",
    "content": "package com.lody.virtual.server.accounts;\n\nimport android.accounts.Account;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SyncAdapterType;\nimport android.content.SyncRequest;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.content.res.XmlResourceParser;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.util.SparseArray;\nimport android.util.Xml;\n\nimport com.lody.virtual.server.pm.VAppManagerService;\nimport com.lody.virtual.server.pm.VPackageManagerService;\n\nimport org.xmlpull.v1.XmlPullParser;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.android.content.SyncAdapterTypeN;\nimport mirror.com.android.internal.R_Hide;\n\n/**\n * @author Lody\n */\n\npublic class VContentService {\n\n    private Context mContext;\n    private final SparseArray<Map<VSyncRecord.SyncRecordKey, VSyncRecord>> mRecords = new SparseArray<>();\n    private final Map<String, SyncAdapterInfo> mAppSyncAdapterInfos = new HashMap<>();\n\n    private class SyncAdapterInfo {\n        SyncAdapterType adapterType;\n        ServiceInfo serviceInfo;\n\n        SyncAdapterInfo(SyncAdapterType adapterType, ServiceInfo serviceInfo) {\n            this.adapterType = adapterType;\n            this.serviceInfo = serviceInfo;\n        }\n    }\n\n    public void refreshServiceCache(String packageName) {\n        Intent intent = new Intent(\"android.content.SyncAdapter\");\n        if (packageName != null) {\n            intent.setPackage(packageName);\n        }\n        generateServicesMap(\n                VPackageManagerService.get().queryIntentServices(\n                        intent, null, PackageManager.GET_META_DATA, 0\n                ),\n                mAppSyncAdapterInfos,\n                new RegisteredServicesParser()\n        );\n    }\n\n    public void syncAsUser(SyncRequest request, int userId) {\n        Account account = mirror.android.content.SyncRequest.mAccountToSync.get(request);\n        String authority = mirror.android.content.SyncRequest.mAuthority.get(request);\n        Bundle extras = mirror.android.content.SyncRequest.mExtras.get(request);\n        boolean isPeriodic = mirror.android.content.SyncRequest.mIsPeriodic.get(request);\n        long syncRunTimeSecs = mirror.android.content.SyncRequest.mSyncRunTimeSecs.get(request);\n        if (!isAccountExist(userId, account, authority)) {\n            return;\n        }\n        VSyncRecord.SyncRecordKey key = new VSyncRecord.SyncRecordKey(account, authority);\n        VSyncRecord.SyncExtras syncExtras = new VSyncRecord.SyncExtras(extras);\n        int isSyncable = getIsSyncableAsUser(account, authority, userId);\n        synchronized (mRecords) {\n            Map<VSyncRecord.SyncRecordKey, VSyncRecord> map = mRecords.get(userId);\n            if (map == null) {\n                map = new HashMap<>();\n                mRecords.put(userId, map);\n            }\n            VSyncRecord record = map.get(key);\n            if (record == null) {\n                record = new VSyncRecord(userId, account, authority);\n                map.put(key, record);\n            }\n            if (isSyncable < 0) {\n                // Initialisation sync.\n                Bundle newExtras = new Bundle();\n                newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);\n                record.extras.add(new VSyncRecord.SyncExtras(newExtras));\n            }\n            if (isPeriodic) {\n                VSyncRecord.PeriodicSyncConfig periodicSyncConfig = new VSyncRecord.PeriodicSyncConfig(syncRunTimeSecs);\n                record.configs.put(syncExtras, periodicSyncConfig);\n            } else {\n                record.extras.add(syncExtras);\n            }\n\n\n        }\n    }\n\n\n    private boolean isAccountExist(int userId, Account account, String providerName) {\n        synchronized (mAppSyncAdapterInfos) {\n            SyncAdapterInfo info = mAppSyncAdapterInfos.get(account.type + \"/\" + providerName);\n            return info != null\n                    && VAppManagerService.get().isAppInstalled(info.serviceInfo.packageName);\n        }\n    }\n\n    public int getIsSyncableAsUser(Account account, String providerName, int userId) {\n        VSyncRecord.SyncRecordKey key = new VSyncRecord.SyncRecordKey(account, providerName);\n        synchronized (mRecords) {\n            Map<VSyncRecord.SyncRecordKey, VSyncRecord> map = mRecords.get(userId);\n            if (map == null) {\n                return -1;\n            }\n            VSyncRecord record = map.get(key);\n            if (record == null) {\n                return -1;\n            }\n            return record.syncable;\n        }\n\n    }\n\n    private void generateServicesMap(List<ResolveInfo> services, Map<String, SyncAdapterInfo> map,\n                                     RegisteredServicesParser accountParser) {\n        for (ResolveInfo info : services) {\n            XmlResourceParser parser = accountParser.getParser(mContext, info.serviceInfo, \"android.content.SyncAdapter\");\n            if (parser != null) {\n                try {\n                    AttributeSet attributeSet = Xml.asAttributeSet(parser);\n                    int type;\n                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {\n                        // Nothing to do\n                    }\n                    if (\"sync-adapter\".equals(parser.getName())) {\n                        SyncAdapterType adapterType = parseSyncAdapterType(\n                                accountParser.getResources(mContext, info.serviceInfo.applicationInfo), attributeSet);\n                        if (adapterType != null) {\n                            String key = adapterType.accountType + \"/\" + adapterType.authority;\n                            map.put(key, new SyncAdapterInfo(adapterType, info.serviceInfo));\n                        }\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    private SyncAdapterType parseSyncAdapterType(Resources res, AttributeSet set) {\n        TypedArray obtainAttributes = res.obtainAttributes(set, R_Hide.styleable.SyncAdapter.get());\n        try {\n            String contentAuthority = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_contentAuthority.get());\n            String accountType = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_accountType.get());\n            if (contentAuthority == null || accountType == null) {\n                obtainAttributes.recycle();\n                return null;\n            }\n            boolean userVisible = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_userVisible.get(), true);\n            boolean supportsUploading = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_supportsUploading.get(), true);\n            boolean isAlwaysSyncable = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_isAlwaysSyncable.get(), true);\n            boolean allowParallelSyncs = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_allowParallelSyncs.get(), true);\n            String settingsActivity = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_settingsActivity.get());\n            SyncAdapterType type;\n            if (SyncAdapterTypeN.ctor != null) {\n                type = SyncAdapterTypeN.ctor.newInstance(contentAuthority, accountType, userVisible, supportsUploading, isAlwaysSyncable, allowParallelSyncs, settingsActivity, null);\n                obtainAttributes.recycle();\n                return type;\n            }\n            type = mirror.android.content.SyncAdapterType.ctor.newInstance(contentAuthority, accountType, userVisible, supportsUploading, isAlwaysSyncable, allowParallelSyncs, settingsActivity);\n            obtainAttributes.recycle();\n            return type;\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/accounts/VSyncRecord.java",
    "content": "package com.lody.virtual.server.accounts;\n\nimport android.accounts.Account;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class VSyncRecord {\n\n    public int userId;\n    public SyncRecordKey key;\n    public int syncable = -1;\n    public boolean isPeriodic = false;\n    public Map<SyncExtras, PeriodicSyncConfig> configs = new HashMap<>();\n    public List<SyncExtras> extras = new ArrayList<>();\n\n    public VSyncRecord(int userId, Account account, String authority) {\n        this.userId = userId;\n        key = new SyncRecordKey(account, authority);\n    }\n\n    public static class SyncExtras implements Parcelable {\n        Bundle extras;\n\n        public SyncExtras(Bundle extras) {\n            this.extras = extras;\n        }\n\n        SyncExtras(Parcel in) {\n            this.extras = in.readBundle(getClass().getClassLoader());\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeBundle(this.extras);\n        }\n\n        public static final Parcelable.Creator<SyncExtras> CREATOR = new Parcelable.Creator<SyncExtras>() {\n            @Override\n            public SyncExtras createFromParcel(Parcel source) {\n                return new SyncExtras(source);\n            }\n\n            @Override\n            public SyncExtras[] newArray(int size) {\n                return new SyncExtras[size];\n            }\n        };\n\n        @Override\n        public boolean equals(Object obj) {\n            return VSyncRecord.equals(this.extras, ((SyncExtras) obj).extras, false);\n        }\n    }\n\n    public static class SyncRecordKey implements Parcelable {\n\n        Account account;\n        String authority;\n\n        SyncRecordKey(Account account, String authority) {\n            this.account = account;\n            this.authority = authority;\n        }\n\n        SyncRecordKey(Parcel in) {\n            this.account = in.readParcelable(Account.class.getClassLoader());\n            this.authority = in.readString();\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeParcelable(this.account, flags);\n            dest.writeString(this.authority);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            SyncRecordKey that = (SyncRecordKey) o;\n\n            if (account != null ? !account.equals(that.account) : that.account != null)\n                return false;\n            return authority != null ? authority.equals(that.authority) : that.authority == null;\n        }\n\n        public static final Parcelable.Creator<SyncRecordKey> CREATOR = new Parcelable.Creator<SyncRecordKey>() {\n            @Override\n            public SyncRecordKey createFromParcel(Parcel source) {\n                return new SyncRecordKey(source);\n            }\n\n            @Override\n            public SyncRecordKey[] newArray(int size) {\n                return new SyncRecordKey[size];\n            }\n        };\n    }\n\n    public static boolean equals(Bundle a, Bundle b, boolean sameSize) {\n        if (a == b) {\n            return true;\n        }\n        if (sameSize && a.size() != b.size()) {\n            return false;\n        }\n        if (a.size() <= b.size()) {\n            Bundle smaller = a;\n            a = b;\n            b = smaller;\n        }\n        for (String key : a.keySet()) {\n            if (sameSize || !isIgnoredKey(key)) {\n                if (!b.containsKey(key)) {\n                    return false;\n                }\n                //noinspection ConstantConditions\n                if (!a.get(key).equals(b.get(key))) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    static class PeriodicSyncConfig implements Parcelable {\n\n        long syncRunTimeSecs;\n\n        public PeriodicSyncConfig(long syncRunTimeSecs) {\n            this.syncRunTimeSecs = syncRunTimeSecs;\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeLong(this.syncRunTimeSecs);\n        }\n\n        PeriodicSyncConfig(Parcel in) {\n            this.syncRunTimeSecs = in.readLong();\n        }\n\n        public static final Parcelable.Creator<PeriodicSyncConfig> CREATOR = new Parcelable.Creator<PeriodicSyncConfig>() {\n            @Override\n            public PeriodicSyncConfig createFromParcel(Parcel source) {\n                return new PeriodicSyncConfig(source);\n            }\n\n            @Override\n            public PeriodicSyncConfig[] newArray(int size) {\n                return new PeriodicSyncConfig[size];\n            }\n        };\n    }\n\n    private static boolean isIgnoredKey(String str) {\n        return str.equals(\"expedited\")\n                || str.equals(\"ignore_settings\")\n                || str.equals(\"ignore_backoff\")\n                || str.equals(\"do_not_retry\")\n                || str.equals(\"force\")\n                || str.equals(\"upload\")\n                || str.equals(\"deletions_override\")\n                || str.equals(\"discard_deletions\")\n                || str.equals(\"expected_upload\")\n                || str.equals(\"expected_download\")\n                || str.equals(\"sync_priority\")\n                || str.equals(\"allow_metered\")\n                || str.equals(\"initialize\");\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ActivityRecord.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.content.ComponentName;\nimport android.os.IBinder;\n\n/**\n * @author Lody\n */\n\n/* package */ class ActivityRecord {\n\tpublic TaskRecord task;\n\tpublic ComponentName component;\n\tpublic ComponentName caller;\n\tpublic IBinder token;\n\tpublic int userId;\n\tpublic ProcessRecord process;\n\tpublic int launchMode;\n\tpublic int flags;\n\tpublic boolean marked;\n\tpublic String affinity;\n\n\tpublic ActivityRecord(TaskRecord task, ComponentName component, ComponentName caller, IBinder token, int userId, ProcessRecord process, int launchMode, int flags, String affinity) {\n\t\tthis.task = task;\n\t\tthis.component = component;\n\t\tthis.caller = caller;\n\t\tthis.token = token;\n\t\tthis.userId = userId;\n\t\tthis.process = process;\n\t\tthis.launchMode = launchMode;\n\t\tthis.flags = flags;\n\t\tthis.affinity = affinity;\n\t}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ActivityStack.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.app.ActivityManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.VirtualRuntime;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.ClassUtils;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.remote.AppTaskInfo;\nimport com.lody.virtual.remote.StubActivityRecord;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.ListIterator;\n\nimport mirror.android.app.ActivityManagerNative;\nimport mirror.android.app.ActivityThread;\nimport mirror.android.app.IActivityManager;\nimport mirror.android.app.IApplicationThread;\nimport mirror.com.android.internal.R_Hide;\n\nimport static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;\nimport static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;\nimport static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;\n\n/**\n * @author Lody\n */\n\n/* package */ class ActivityStack {\n\n    private final ActivityManager mAM;\n    private final VActivityManagerService mService;\n\n    /**\n     * [Key] = TaskId [Value] = TaskRecord\n     */\n    private final SparseArray<TaskRecord> mHistory = new SparseArray<>();\n\n\n    ActivityStack(VActivityManagerService mService) {\n        this.mService = mService;\n        mAM = (ActivityManager) VirtualCore.get().getContext().getSystemService(Context.ACTIVITY_SERVICE);\n    }\n\n    private static void removeFlags(Intent intent, int flags) {\n        intent.setFlags(intent.getFlags() & ~flags);\n    }\n\n    private static boolean containFlags(Intent intent, int flags) {\n        return (intent.getFlags() & flags) != 0;\n    }\n\n    private static ActivityRecord topActivityInTask(TaskRecord task) {\n        synchronized (task.activities) {\n            for (int size = task.activities.size() - 1; size >= 0; size--) {\n                ActivityRecord r = task.activities.get(size);\n                if (!r.marked) {\n                    return r;\n                }\n            }\n            return null;\n        }\n    }\n\n\n    private void deliverNewIntentLocked(ActivityRecord sourceRecord, ActivityRecord targetRecord, Intent intent) {\n        if (targetRecord == null) {\n            return;\n        }\n        String creator = sourceRecord != null ? sourceRecord.component.getPackageName() : \"android\";\n        try {\n            targetRecord.process.client.scheduleNewIntent(creator, targetRecord.token, intent);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        } catch (NullPointerException npe) {\n            npe.printStackTrace();\n        }\n    }\n\n    private TaskRecord findTaskByAffinityLocked(int userId, String affinity) {\n        for (int i = 0; i < this.mHistory.size(); i++) {\n            TaskRecord r = this.mHistory.valueAt(i);\n            if (userId == r.userId && affinity.equals(r.affinity)) {\n                return r;\n            }\n        }\n        return null;\n    }\n\n    private TaskRecord findTaskByIntentLocked(int userId, Intent intent) {\n        for (int i = 0; i < this.mHistory.size(); i++) {\n            TaskRecord r = this.mHistory.valueAt(i);\n            if (userId == r.userId && r.taskRoot != null && intent.getComponent().equals(r.taskRoot.getComponent())) {\n                return r;\n            }\n        }\n        return null;\n    }\n\n    private ActivityRecord findActivityByToken(int userId, IBinder token) {\n        ActivityRecord target = null;\n        if (token != null) {\n            for (int i = 0; i < this.mHistory.size(); i++) {\n                TaskRecord task = this.mHistory.valueAt(i);\n                if (task.userId != userId) {\n                    continue;\n                }\n                synchronized (task.activities) {\n                    for (ActivityRecord r : task.activities) {\n                        if (r.token == token) {\n                            target = r;\n                        }\n                    }\n                }\n            }\n        }\n        return target;\n    }\n\n    private boolean markTaskByClearTarget(TaskRecord task, ClearTarget clearTarget, ComponentName component) {\n        boolean marked = false;\n        synchronized (task.activities) {\n            switch (clearTarget) {\n                case TASK: {\n                    for (ActivityRecord r : task.activities) {\n                        r.marked = true;\n                        marked = true;\n                    }\n                }\n                break;\n                case SPEC_ACTIVITY: {\n                    for (ActivityRecord r : task.activities) {\n                        if (r.component.equals(component)) {\n                            r.marked = true;\n                            marked = true;\n                        }\n                    }\n                }\n                break;\n                case TOP: {\n                    int N = task.activities.size();\n                    while (N-- > 0) {\n                        ActivityRecord r = task.activities.get(N);\n                        if (r.component.equals(component)) {\n                            marked = true;\n                            break;\n                        }\n                    }\n                    if (marked) {\n                        while (N++ < task.activities.size() - 1) {\n                            task.activities.get(N).marked = true;\n                        }\n                    }\n                }\n                break;\n            }\n        }\n        return marked;\n    }\n\n    /**\n     * App started in VA may be removed in OverView screen, then AMS.removeTask\n     * will be invoked, all data struct about the task in AMS are released,\n     * while the client's process is still alive. So remove related data in VA\n     * as well. A new TaskRecord will be recreated in `onActivityCreated`\n     */\n    private void optimizeTasksLocked() {\n        // noinspection deprecation\n        ArrayList<ActivityManager.RecentTaskInfo> recentTask = new ArrayList<>(mAM.getRecentTasks(Integer.MAX_VALUE,\n                ActivityManager.RECENT_WITH_EXCLUDED | ActivityManager.RECENT_IGNORE_UNAVAILABLE));\n        int N = mHistory.size();\n        while (N-- > 0) {\n            TaskRecord task = mHistory.valueAt(N);\n            ListIterator<ActivityManager.RecentTaskInfo> iterator = recentTask.listIterator();\n            boolean taskAlive = false;\n            while (iterator.hasNext()) {\n                ActivityManager.RecentTaskInfo info = iterator.next();\n                if (info.id == task.taskId) {\n                    taskAlive = true;\n                    iterator.remove();\n                    break;\n                }\n            }\n            if (!taskAlive) {\n                mHistory.removeAt(N);\n            }\n        }\n    }\n\n\n    int startActivitiesLocked(int userId, Intent[] intents, ActivityInfo[] infos, String[] resolvedTypes, IBinder token, Bundle options) {\n        optimizeTasksLocked();\n        ReuseTarget reuseTarget = ReuseTarget.CURRENT;\n        Intent intent = intents[0];\n        ActivityInfo info = infos[0];\n        ActivityRecord resultTo = findActivityByToken(userId, token);\n        if (resultTo != null && resultTo.launchMode == LAUNCH_SINGLE_INSTANCE) {\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        }\n        if (containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP)) {\n            removeFlags(intent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);\n        }\n        if (containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK) && !containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {\n            removeFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            switch (info.documentLaunchMode) {\n                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:\n                    reuseTarget = ReuseTarget.DOCUMENT;\n                    break;\n                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:\n                    reuseTarget = ReuseTarget.MULTIPLE;\n                    break;\n            }\n        }\n        if (containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {\n            reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK) ? ReuseTarget.MULTIPLE : ReuseTarget.AFFINITY;\n        } else if (info.launchMode == LAUNCH_SINGLE_TASK) {\n            reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK) ? ReuseTarget.MULTIPLE : ReuseTarget.AFFINITY;\n        }\n        if (resultTo == null && reuseTarget == ReuseTarget.CURRENT) {\n            reuseTarget = ReuseTarget.AFFINITY;\n        }\n        String affinity = ComponentUtils.getTaskAffinity(info);\n        TaskRecord reuseTask = null;\n        if (reuseTarget == ReuseTarget.AFFINITY) {\n            reuseTask = findTaskByAffinityLocked(userId, affinity);\n        } else if (reuseTarget == ReuseTarget.CURRENT) {\n            reuseTask = resultTo.task;\n        } else if (reuseTarget == ReuseTarget.DOCUMENT) {\n            reuseTask = findTaskByIntentLocked(userId, intent);\n        }\n        Intent[] destIntents = startActivitiesProcess(userId, intents, infos, resultTo);\n        if (reuseTask == null) {\n            realStartActivitiesLocked(null, destIntents, resolvedTypes, options);\n        } else {\n            ActivityRecord top = topActivityInTask(reuseTask);\n            if (top != null) {\n                realStartActivitiesLocked(top.token, destIntents, resolvedTypes, options);\n            }\n        }\n        return 0;\n    }\n\n    private Intent[] startActivitiesProcess(int userId, Intent[] intents, ActivityInfo[] infos, ActivityRecord resultTo) {\n        Intent[] destIntents = new Intent[intents.length];\n        for (int i = 0; i < intents.length; i++) {\n            destIntents[i] = startActivityProcess(userId, resultTo, intents[i], infos[i]);\n        }\n        return destIntents;\n    }\n\n\n    int startActivityLocked(int userId, Intent intent, ActivityInfo info, IBinder resultTo, Bundle options,\n                            String resultWho, int requestCode) {\n        optimizeTasksLocked();\n\n        Intent destIntent;\n        ActivityRecord sourceRecord = findActivityByToken(userId, resultTo);\n        TaskRecord sourceTask = sourceRecord != null ? sourceRecord.task : null;\n\n        ReuseTarget reuseTarget = ReuseTarget.CURRENT;\n        ClearTarget clearTarget = ClearTarget.NOTHING;\n        boolean clearTop = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        boolean clearTask = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);\n\n        if (intent.getComponent() == null) {\n            intent.setComponent(new ComponentName(info.packageName, info.name));\n        }\n        if (sourceRecord != null && sourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        }\n        if (clearTop) {\n            removeFlags(intent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);\n            clearTarget = ClearTarget.TOP;\n        }\n        if (clearTask) {\n            if (containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {\n                clearTarget = ClearTarget.TASK;\n            } else {\n                removeFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);\n            }\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            switch (info.documentLaunchMode) {\n                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:\n                    clearTarget = ClearTarget.TASK;\n                    reuseTarget = ReuseTarget.DOCUMENT;\n                    break;\n                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:\n                    reuseTarget = ReuseTarget.MULTIPLE;\n                    break;\n            }\n        }\n        boolean singleTop = false;\n\n        switch (info.launchMode) {\n            case LAUNCH_SINGLE_TOP: {\n                singleTop = true;\n                if (containFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK)) {\n                    reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK)\n                            ? ReuseTarget.MULTIPLE\n                            : ReuseTarget.AFFINITY;\n                }\n            }\n            break;\n            case LAUNCH_SINGLE_TASK: {\n                clearTop = false;\n                clearTarget = ClearTarget.TOP;\n                reuseTarget = containFlags(intent, Intent.FLAG_ACTIVITY_MULTIPLE_TASK)\n                        ? ReuseTarget.MULTIPLE\n                        : ReuseTarget.AFFINITY;\n            }\n            break;\n            case LAUNCH_SINGLE_INSTANCE: {\n                clearTop = false;\n                clearTarget = ClearTarget.TOP;\n                reuseTarget = ReuseTarget.AFFINITY;\n            }\n            break;\n            default: {\n                if (containFlags(intent, Intent.FLAG_ACTIVITY_SINGLE_TOP)) {\n                    singleTop = true;\n                }\n            }\n            break;\n        }\n        if (clearTarget == ClearTarget.NOTHING) {\n            if (containFlags(intent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)) {\n                clearTarget = ClearTarget.SPEC_ACTIVITY;\n            }\n        }\n        if (sourceTask == null && reuseTarget == ReuseTarget.CURRENT) {\n            reuseTarget = ReuseTarget.AFFINITY;\n        }\n\n        String affinity = ComponentUtils.getTaskAffinity(info);\n        TaskRecord reuseTask = null;\n        switch (reuseTarget) {\n            case AFFINITY:\n                reuseTask = findTaskByAffinityLocked(userId, affinity);\n                break;\n            case DOCUMENT:\n                reuseTask = findTaskByIntentLocked(userId, intent);\n                break;\n            case CURRENT:\n                reuseTask = sourceTask;\n                break;\n            default:\n                break;\n        }\n\n        boolean taskMarked = false;\n        if (reuseTask == null) {\n            startActivityInNewTaskLocked(userId, intent, info, options);\n        } else {\n            boolean delivered = false;\n            mAM.moveTaskToFront(reuseTask.taskId, 0);\n            boolean startTaskToFront = !clearTask && !clearTop && ComponentUtils.isSameIntent(intent, reuseTask.taskRoot);\n\n            if (clearTarget.deliverIntent || singleTop) {\n                taskMarked = markTaskByClearTarget(reuseTask, clearTarget, intent.getComponent());\n                ActivityRecord topRecord = topActivityInTask(reuseTask);\n                if (clearTop && !singleTop && topRecord != null && taskMarked) {\n                    topRecord.marked = true;\n                }\n                // Target activity is on top\n                if (topRecord != null && !topRecord.marked && topRecord.component.equals(intent.getComponent())) {\n                    deliverNewIntentLocked(sourceRecord, topRecord, intent);\n                    delivered = true;\n                }\n            }\n            if (taskMarked) {\n                synchronized (mHistory) {\n                    scheduleFinishMarkedActivityLocked();\n                }\n            }\n            if (!startTaskToFront) {\n                if (!delivered) {\n                    destIntent = startActivityProcess(userId, sourceRecord, intent, info);\n                    if (destIntent != null) {\n                        startActivityFromSourceTask(reuseTask, destIntent, info, resultWho, requestCode, options);\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n    private void startActivityInNewTaskLocked(int userId, Intent intent, ActivityInfo info, Bundle options) {\n        Intent destIntent = startActivityProcess(userId, null, intent, info);\n        if (destIntent != null) {\n            destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            destIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n            destIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {\n                // noinspection deprecation\n                destIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);\n            } else {\n                destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);\n            }\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                VirtualCore.get().getContext().startActivity(destIntent, options);\n            } else {\n                VirtualCore.get().getContext().startActivity(destIntent);\n            }\n        }\n    }\n\n    private void scheduleFinishMarkedActivityLocked() {\n        int N = mHistory.size();\n        while (N-- > 0) {\n            final TaskRecord task = mHistory.valueAt(N);\n            for (final ActivityRecord r : task.activities) {\n                if (!r.marked) {\n                    continue;\n                }\n                VirtualRuntime.getUIHandler().post(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            r.process.client.finishActivity(r.token);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                });\n            }\n        }\n    }\n\n    private void startActivityFromSourceTask(TaskRecord task, Intent intent, ActivityInfo info, String resultWho,\n                                             int requestCode, Bundle options) {\n        ActivityRecord top = task.activities.isEmpty() ? null : task.activities.get(task.activities.size() - 1);\n        if (top != null) {\n            if (startActivityProcess(task.userId, top, intent, info) != null) {\n                realStartActivityLocked(top.token, intent, resultWho, requestCode, options);\n            }\n        }\n    }\n\n\n    private void realStartActivitiesLocked(IBinder resultTo, Intent[] intents, String[] resolvedTypes, Bundle options) {\n        Class<?>[] types = IActivityManager.startActivities.paramList();\n        Object[] args = new Object[types.length];\n        if (types[0] == IApplicationThread.TYPE) {\n            args[0] = ActivityThread.getApplicationThread.call(VirtualCore.mainThread());\n        }\n        int pkgIndex = ArrayUtils.protoIndexOf(types, String.class);\n        int intentsIndex = ArrayUtils.protoIndexOf(types, Intent[].class);\n        int resultToIndex = ArrayUtils.protoIndexOf(types, IBinder.class, 2);\n        int optionsIndex = ArrayUtils.protoIndexOf(types, Bundle.class);\n        int resolvedTypesIndex = intentsIndex + 1;\n        if (pkgIndex != -1) {\n            args[pkgIndex] = VirtualCore.get().getHostPkg();\n        }\n        args[intentsIndex] = intents;\n        args[resultToIndex] = resultTo;\n        args[resolvedTypesIndex] = resolvedTypes;\n        args[optionsIndex] = options;\n        ClassUtils.fixArgs(types, args);\n        IActivityManager.startActivities.call(ActivityManagerNative.getDefault.call(),\n                (Object[]) args);\n    }\n\n    private void realStartActivityLocked(IBinder resultTo, Intent intent, String resultWho, int requestCode,\n                                         Bundle options) {\n        Class<?>[] types = mirror.android.app.IActivityManager.startActivity.paramList();\n        Object[] args = new Object[types.length];\n        if (types[0] == IApplicationThread.TYPE) {\n            args[0] = ActivityThread.getApplicationThread.call(VirtualCore.mainThread());\n        }\n        int intentIndex = ArrayUtils.protoIndexOf(types, Intent.class);\n        int resultToIndex = ArrayUtils.protoIndexOf(types, IBinder.class, 2);\n        int optionsIndex = ArrayUtils.protoIndexOf(types, Bundle.class);\n        int resolvedTypeIndex = intentIndex + 1;\n        int resultWhoIndex = resultToIndex + 1;\n        int requestCodeIndex = resultToIndex + 2;\n\n        args[intentIndex] = intent;\n        args[resultToIndex] = resultTo;\n        args[resultWhoIndex] = resultWho;\n        args[requestCodeIndex] = requestCode;\n        if (optionsIndex != -1) {\n            args[optionsIndex] = options;\n        }\n        args[resolvedTypeIndex] = intent.getType();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            args[intentIndex - 1] = VirtualCore.get().getHostPkg();\n        }\n        ClassUtils.fixArgs(types, args);\n\n        mirror.android.app.IActivityManager.startActivity.call(ActivityManagerNative.getDefault.call(),\n                (Object[]) args);\n    }\n\n    private String fetchStubActivity(int vpid, ActivityInfo targetInfo) {\n\n        boolean isFloating = false;\n        boolean isTranslucent = false;\n        boolean showWallpaper = false;\n        try {\n            int[] R_Styleable_Window = R_Hide.styleable.Window.get();\n            int R_Styleable_Window_windowIsTranslucent = R_Hide.styleable.Window_windowIsTranslucent.get();\n            int R_Styleable_Window_windowIsFloating = R_Hide.styleable.Window_windowIsFloating.get();\n            int R_Styleable_Window_windowShowWallpaper = R_Hide.styleable.Window_windowShowWallpaper.get();\n\n            AttributeCache.Entry ent = AttributeCache.instance().get(targetInfo.packageName, targetInfo.theme,\n                    R_Styleable_Window);\n            if (ent != null && ent.array != null) {\n                showWallpaper = ent.array.getBoolean(R_Styleable_Window_windowShowWallpaper, false);\n                isTranslucent = ent.array.getBoolean(R_Styleable_Window_windowIsTranslucent, false);\n                isFloating = ent.array.getBoolean(R_Styleable_Window_windowIsFloating, false);\n            }else{\n                Resources resources=VirtualCore.get().getResources(targetInfo.packageName);\n                if(resources!=null) {\n                    TypedArray typedArray = resources.newTheme().obtainStyledAttributes(targetInfo.theme, R_Styleable_Window);\n                    if(typedArray!=null){\n                        showWallpaper = typedArray.getBoolean(R_Styleable_Window_windowShowWallpaper, false);\n                        isTranslucent = typedArray.getBoolean(R_Styleable_Window_windowIsTranslucent, false);\n                        isFloating = typedArray.getBoolean(R_Styleable_Window_windowIsFloating, false);\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n\n        // deal with manifest Activity style android:excludeFromRecents=\"true\", becasue Mobile Legends has two recent task\n        boolean isExcludeFromRecents = ((targetInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0);\n        if (isExcludeFromRecents) {\n            return VASettings.getStubExcludeFromRecentActivityName(vpid);\n        }\n\n        boolean isDialogStyle = isFloating || isTranslucent || showWallpaper;\n        if (isDialogStyle) {\n            return VASettings.getStubDialogName(vpid);\n        } else {\n            return VASettings.getStubActivityName(vpid);\n        }\n    }\n\n    private Intent startActivityProcess(int userId, ActivityRecord sourceRecord, Intent intent, ActivityInfo info) {\n        intent = new Intent(intent);\n        ProcessRecord targetApp = mService.startProcessIfNeedLocked(info.processName, userId, info.packageName);\n        if (targetApp == null) {\n            return null;\n        }\n        Intent targetIntent = new Intent();\n        targetIntent.setClassName(VirtualCore.get().getHostPkg(), fetchStubActivity(targetApp.vpid, info));\n        ComponentName component = intent.getComponent();\n        if (component == null) {\n            component = ComponentUtils.toComponentName(info);\n        }\n        targetIntent.setType(component.flattenToString());\n        StubActivityRecord saveInstance = new StubActivityRecord(intent, info,\n                sourceRecord != null ? sourceRecord.component : null, userId);\n        saveInstance.saveToIntent(targetIntent);\n        return targetIntent;\n    }\n\n    void onActivityCreated(ProcessRecord targetApp, ComponentName component, ComponentName caller, IBinder token,\n                           Intent taskRoot, String affinity, int taskId, int launchMode, int flags) {\n        synchronized (mHistory) {\n            optimizeTasksLocked();\n            TaskRecord task = mHistory.get(taskId);\n            if (task == null) {\n                task = new TaskRecord(taskId, targetApp.userId, affinity, taskRoot);\n                mHistory.put(taskId, task);\n            }\n            ActivityRecord record = new ActivityRecord(task, component, caller, token, targetApp.userId, targetApp,\n                    launchMode, flags, affinity);\n            synchronized (task.activities) {\n                task.activities.add(record);\n            }\n        }\n    }\n\n    void onActivityResumed(int userId, IBinder token) {\n        synchronized (mHistory) {\n            optimizeTasksLocked();\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                synchronized (r.task.activities) {\n                    r.task.activities.remove(r);\n                    r.task.activities.add(r);\n                }\n            }\n        }\n    }\n\n    ActivityRecord onActivityDestroyed(int userId, IBinder token) {\n        synchronized (mHistory) {\n            optimizeTasksLocked();\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                synchronized (r.task.activities) {\n                    r.task.activities.remove(r);\n                    // We shouldn't remove task at this point,\n                    // it will be removed by optimizeTasksLocked().\n                }\n            }\n            return r;\n        }\n    }\n\n    void processDied(ProcessRecord record) {\n        synchronized (mHistory) {\n            optimizeTasksLocked();\n            int N = mHistory.size();\n            while (N-- > 0) {\n                TaskRecord task = mHistory.valueAt(N);\n                synchronized (task.activities) {\n                    Iterator<ActivityRecord> iterator = task.activities.iterator();\n                    while (iterator.hasNext()) {\n                        ActivityRecord r = iterator.next();\n                        if (r.process.pid == record.pid) {\n                            iterator.remove();\n                            if (task.activities.isEmpty()) {\n                                mHistory.remove(task.taskId);\n                            }\n                        }\n                    }\n                }\n            }\n\n        }\n    }\n\n    String getPackageForToken(int userId, IBinder token) {\n        synchronized (mHistory) {\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                return r.component.getPackageName();\n            }\n            return null;\n        }\n    }\n\n    ComponentName getCallingActivity(int userId, IBinder token) {\n        synchronized (mHistory) {\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                return r.caller != null ? r.caller : r.component;\n            }\n            return null;\n        }\n    }\n\n    public String getCallingPackage(int userId, IBinder token) {\n        synchronized (mHistory) {\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                return r.caller != null ? r.caller.getPackageName() : \"android\";\n            }\n            return \"android\";\n        }\n    }\n\n    AppTaskInfo getTaskInfo(int taskId) {\n        synchronized (mHistory) {\n            TaskRecord task = mHistory.get(taskId);\n            if (task != null) {\n                return task.getAppTaskInfo();\n            }\n            return null;\n        }\n    }\n\n    ComponentName getActivityClassForToken(int userId, IBinder token) {\n        synchronized (mHistory) {\n            ActivityRecord r = findActivityByToken(userId, token);\n            if (r != null) {\n                return r.component;\n            }\n            return null;\n        }\n    }\n\n    private enum ClearTarget {\n        NOTHING,\n        SPEC_ACTIVITY,\n        TASK(true),\n        TOP(true);\n\n        boolean deliverIntent;\n\n        ClearTarget() {\n            this(false);\n        }\n\n        ClearTarget(boolean deliverIntent) {\n            this.deliverIntent = deliverIntent;\n        }\n    }\n\n    private enum ReuseTarget {\n        CURRENT, AFFINITY, DOCUMENT, MULTIPLE\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/AppBindRecord.java",
    "content": "/*\n * Copyright (C) 2006 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.server.am;\n\nimport java.util.HashSet;\n\n/**\n * An association between a service and one of its client applications.\n */\nfinal class AppBindRecord {\n    final ServiceRecord service;    // The running service.\n    final ServiceRecord.IntentBindRecord intent;  // The intent we are bound to.\n    final ProcessRecord client;     // Who has started/bound the service.\n\n    final HashSet<ConnectionRecord> connections = new HashSet<ConnectionRecord>();\n                                    // All ConnectionRecord for this client.\n\n    AppBindRecord(ServiceRecord _service, ServiceRecord.IntentBindRecord _intent,\n            ProcessRecord _client) {\n        service = _service;\n        intent = _intent;\n        client = _client;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/AttributeCache.java",
    "content": "/*\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n\npackage com.lody.virtual.server.am;\n\nimport java.util.HashMap;\nimport java.util.WeakHashMap;\n\nimport android.content.Context;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.util.SparseArray;\n\n/**\n * TODO: This should be better integrated into the system so it doesn't need\n * special calls from the activity manager to clear it.\n */\npublic final class AttributeCache {\n\tprivate static AttributeCache sInstance = null;\n\n\tprivate final Context mContext;\n\tprivate final WeakHashMap<String, Package> mPackages = new WeakHashMap<String, Package>();\n\tprivate final Configuration mConfiguration = new Configuration();\n\n\tpublic AttributeCache(Context context) {\n\t\tmContext = context;\n\t}\n\n\tpublic static void init(Context context) {\n\t\tif (sInstance == null) {\n\t\t\tsInstance = new AttributeCache(context);\n\t\t}\n\t}\n\n\tpublic static AttributeCache instance() {\n\t\treturn sInstance;\n\t}\n\n\tpublic void removePackage(String packageName) {\n\t\tsynchronized (this) {\n\t\t\tmPackages.remove(packageName);\n\t\t}\n\t}\n\n\tpublic void updateConfiguration(Configuration config) {\n\t\tsynchronized (this) {\n\t\t\tint changes = mConfiguration.updateFrom(config);\n\t\t\tif ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_KEYBOARD_HIDDEN\n\t\t\t\t\t| ActivityInfo.CONFIG_ORIENTATION)) != 0) {\n\t\t\t\t// The configurations being masked out are ones that commonly\n\t\t\t\t// change so we don't want flushing the cache... all others\n\t\t\t\t// will flush the cache.\n\t\t\t\tmPackages.clear();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic Entry get(String packageName, int resId, int[] styleable) {\n\t\tsynchronized (this) {\n\t\t\tPackage pkg = mPackages.get(packageName);\n\t\t\tHashMap<int[], Entry> map = null;\n\t\t\tEntry ent = null;\n\t\t\tif (pkg != null) {\n\t\t\t\tmap = pkg.mMap.get(resId);\n\t\t\t\tif (map != null) {\n\t\t\t\t\tent = map.get(styleable);\n\t\t\t\t\tif (ent != null) {\n\t\t\t\t\t\treturn ent;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tContext context;\n\t\t\t\ttry {\n\t\t\t\t\tcontext = mContext.createPackageContext(packageName,\n\t\t\t\t\t\t\tContext.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);\n\t\t\t\t\tif (context == null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t} catch (PackageManager.NameNotFoundException e) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tpkg = new Package(context);\n\t\t\t\tmPackages.put(packageName, pkg);\n\t\t\t}\n\n\t\t\tif (map == null) {\n\t\t\t\tmap = new HashMap<int[], Entry>();\n\t\t\t\tpkg.mMap.put(resId, map);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tent = new Entry(pkg.context, pkg.context.obtainStyledAttributes(resId, styleable));\n\t\t\t\tmap.put(styleable, ent);\n\t\t\t} catch (Resources.NotFoundException e) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn ent;\n\t\t}\n\t}\n\n\tpublic final static class Package {\n\t\tpublic final Context context;\n\t\tprivate final SparseArray<HashMap<int[], Entry>> mMap = new SparseArray<HashMap<int[], Entry>>();\n\n\t\tpublic Package(Context c) {\n\t\t\tcontext = c;\n\t\t}\n\t}\n\n\tpublic final static class Entry {\n\t\tpublic final Context context;\n\t\tpublic final TypedArray array;\n\n\t\tpublic Entry(Context c, TypedArray ta) {\n\t\t\tcontext = c;\n\t\t\tarray = ta;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/BroadcastSystem.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Message;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.SpecialComponentList;\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.remote.PendingResultData;\nimport com.lody.virtual.server.pm.PackageSetting;\nimport com.lody.virtual.server.pm.VAppManagerService;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.android.app.ContextImpl;\nimport mirror.android.app.LoadedApkHuaWei;\nimport mirror.android.rms.resource.ReceiverResourceLP;\nimport mirror.android.rms.resource.ReceiverResourceM;\nimport mirror.android.rms.resource.ReceiverResourceN;\n\nimport static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;\n\n/**\n * @author Lody\n */\n\npublic class BroadcastSystem {\n\n    private static final String TAG = BroadcastSystem.class.getSimpleName();\n    /**\n     * MUST < 10000.\n     */\n    private static final int BROADCAST_TIME_OUT = 8500;\n    private static BroadcastSystem gDefault;\n\n    private final ArrayMap<String, List<BroadcastReceiver>> mReceivers = new ArrayMap<>();\n    private final Map<IBinder, BroadcastRecord> mBroadcastRecords = new HashMap<>();\n    private final Context mContext;\n    private final StaticScheduler mScheduler;\n    private final TimeoutHandler mTimeoutHandler;\n    private final VActivityManagerService mAMS;\n    private final VAppManagerService mApp;\n\n    private BroadcastSystem(Context context, VActivityManagerService ams, VAppManagerService app) {\n        this.mContext = context;\n        this.mApp = app;\n        this.mAMS = ams;\n        mScheduler = new StaticScheduler();\n        mTimeoutHandler = new TimeoutHandler();\n        fuckHuaWeiVerifier();\n    }\n\n    public static void attach(VActivityManagerService ams, VAppManagerService app) {\n        if (gDefault != null) {\n            throw new IllegalStateException();\n        }\n        gDefault = new BroadcastSystem(VirtualCore.get().getContext(), ams, app);\n    }\n\n    public static BroadcastSystem get() {\n        return gDefault;\n    }\n\n    /**\n     * FIX ISSUE #171:\n     * java.lang.AssertionError: Register too many Broadcast Receivers\n     * at android.app.LoadedApk.checkRecevierRegisteredLeakLocked(LoadedApk.java:772)\n     * at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:800)\n     * at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1329)\n     * at android.app.ContextImpl.registerReceiver(ContextImpl.java:1309)\n     * at com.lody.virtual.server.am.BroadcastSystem.startApp(BroadcastSystem.java:54)\n     * at com.lody.virtual.server.pm.VAppManagerService.install(VAppManagerService.java:193)\n     * at com.lody.virtual.server.pm.VAppManagerService.preloadAllApps(VAppManagerService.java:98)\n     * at com.lody.virtual.server.pm.VAppManagerService.systemReady(VAppManagerService.java:70)\n     * at com.lody.virtual.server.BinderProvider.onCreate(BinderProvider.java:42)\n     */\n    private void fuckHuaWeiVerifier() {\n\n        if (LoadedApkHuaWei.mReceiverResource != null) {\n            Object packageInfo = ContextImpl.mPackageInfo.get(mContext);\n            if (packageInfo != null) {\n                Object receiverResource = LoadedApkHuaWei.mReceiverResource.get(packageInfo);\n                if (receiverResource != null) {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                        if (ReceiverResourceN.mWhiteList != null) {\n                            List<String> whiteList = ReceiverResourceN.mWhiteList.get(receiverResource);\n                            List<String> newWhiteList = new ArrayList<>();\n                            // Add our package name to the white list.\n                            newWhiteList.add(mContext.getPackageName());\n                            if (whiteList != null) {\n                                newWhiteList.addAll(whiteList);\n                            }\n                            ReceiverResourceN.mWhiteList.set(receiverResource, newWhiteList);\n                        }\n\n                    } else {\n                        if (ReceiverResourceM.mWhiteList != null) {\n                            String[] whiteList = ReceiverResourceM.mWhiteList.get(receiverResource);\n                            List<String> newWhiteList = new LinkedList<>();\n                            Collections.addAll(newWhiteList, whiteList);\n                            // Add our package name to the white list.\n                            newWhiteList.add(mContext.getPackageName());\n                            ReceiverResourceM.mWhiteList.set(receiverResource, newWhiteList.toArray(new String[newWhiteList.size()]));\n                        } else if (ReceiverResourceLP.mResourceConfig != null) {\n                            // Just clear the ResourceConfig.\n                            ReceiverResourceLP.mResourceConfig.set(receiverResource, null);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public void startApp(VPackage p) {\n        PackageSetting setting = (PackageSetting) p.mExtras;\n        for (VPackage.ActivityComponent receiver : p.receivers) {\n            ActivityInfo info = receiver.info;\n            List<BroadcastReceiver> receivers = mReceivers.get(p.packageName);\n            if (receivers == null) {\n                receivers = new ArrayList<>();\n                mReceivers.put(p.packageName, receivers);\n            }\n            String componentAction = String.format(\"_VA_%s_%s\", info.packageName, info.name);\n            IntentFilter componentFilter = new IntentFilter(componentAction);\n            BroadcastReceiver r = new StaticBroadcastReceiver(setting.appId, info, componentFilter);\n            mContext.registerReceiver(r, componentFilter, null, mScheduler);\n            receivers.add(r);\n            for (VPackage.ActivityIntentInfo ci : receiver.intents) {\n                IntentFilter cloneFilter = new IntentFilter(ci.filter);\n                SpecialComponentList.protectIntentFilter(cloneFilter);\n                r = new StaticBroadcastReceiver(setting.appId, info, cloneFilter);\n                mContext.registerReceiver(r, cloneFilter, null, mScheduler);\n                receivers.add(r);\n            }\n        }\n    }\n\n\n    public void stopApp(String packageName) {\n        synchronized (mBroadcastRecords) {\n            Iterator<Map.Entry<IBinder, BroadcastRecord>> iterator = mBroadcastRecords.entrySet().iterator();\n            while (iterator.hasNext()) {\n                Map.Entry<IBinder, BroadcastRecord> entry = iterator.next();\n                BroadcastRecord record = entry.getValue();\n                if (record.receiverInfo.packageName.equals(packageName)) {\n                    record.pendingResult.finish();\n                    iterator.remove();\n                }\n            }\n        }\n        synchronized (mReceivers) {\n            List<BroadcastReceiver> receivers = mReceivers.get(packageName);\n            if (receivers != null) {\n                for (BroadcastReceiver r : receivers) {\n                    mContext.unregisterReceiver(r);\n                }\n            }\n            mReceivers.remove(packageName);\n        }\n    }\n\n    void broadcastFinish(PendingResultData res) {\n        synchronized (mBroadcastRecords) {\n            BroadcastRecord record = mBroadcastRecords.remove(res.mToken);\n            if (record == null) {\n                VLog.e(TAG, \"Unable to find the BroadcastRecord by token: \" + res.mToken);\n            }\n        }\n        mTimeoutHandler.removeMessages(0, res.mToken);\n        res.finish();\n    }\n\n    void broadcastSent(int vuid, ActivityInfo receiverInfo, PendingResultData res) {\n        BroadcastRecord record = new BroadcastRecord(vuid, receiverInfo, res);\n        synchronized (mBroadcastRecords) {\n            mBroadcastRecords.put(res.mToken, record);\n        }\n        Message msg = new Message();\n        msg.obj = res.mToken;\n        mTimeoutHandler.sendMessageDelayed(msg, BROADCAST_TIME_OUT);\n    }\n\n    private static final class StaticScheduler extends Handler {\n\n    }\n\n    private static final class BroadcastRecord {\n        int vuid;\n        ActivityInfo receiverInfo;\n        PendingResultData pendingResult;\n\n        BroadcastRecord(int vuid, ActivityInfo receiverInfo, PendingResultData pendingResult) {\n            this.vuid = vuid;\n            this.receiverInfo = receiverInfo;\n            this.pendingResult = pendingResult;\n        }\n    }\n\n    private final class TimeoutHandler extends Handler {\n        @Override\n        public void handleMessage(Message msg) {\n            IBinder token = (IBinder) msg.obj;\n            BroadcastRecord r = mBroadcastRecords.remove(token);\n            if (r != null) {\n                VLog.w(TAG, \"Broadcast timeout, cancel to dispatch it.\");\n                r.pendingResult.finish();\n            }\n        }\n    }\n\n\n    private final class StaticBroadcastReceiver extends BroadcastReceiver {\n        private int appId;\n        private ActivityInfo info;\n        @SuppressWarnings(\"unused\")\n        private IntentFilter filter;\n\n        private StaticBroadcastReceiver(int appId, ActivityInfo info, IntentFilter filter) {\n            this.appId = appId;\n            this.info = info;\n            this.filter = filter;\n        }\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (mApp.isBooting()) {\n                return;\n            }\n            if ((intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) != 0 || isInitialStickyBroadcast()) {\n                return;\n            }\n            String privilegePkg = intent.getStringExtra(\"_VA_|_privilege_pkg_\");\n            if (privilegePkg != null && !info.packageName.equals(privilegePkg)) {\n                return;\n            }\n            PendingResult result = goAsync();\n            if (!mAMS.handleStaticBroadcast(appId, info, intent, new PendingResultData(result))) {\n                result.finish();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ConnectionRecord.java",
    "content": "/*\n * Copyright (C) 2006 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.server.am;\n\nimport android.app.IServiceConnection;\n\n/**\n * Description of a single binding to a service.\n */\nfinal class ConnectionRecord {\n    final AppBindRecord binding;    // The application/service binding.\n    final IServiceConnection conn;  // The client connection.\n    final int flags;                // Binding options.\n    boolean serviceDead;            // Well is it?\n\n    ConnectionRecord(AppBindRecord _binding,\n               IServiceConnection _conn, int _flags) {\n        binding = _binding;\n        conn = _conn;\n        flags = _flags;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/PendingIntents.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.remote.PendingIntentData;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n\n/**\n * @author Lody\n */\npublic final class PendingIntents {\n\n    private final Map<IBinder, PendingIntentData> mLruHistory = new HashMap<>();\n\n    final PendingIntentData getPendingIntent(IBinder binder) {\n        synchronized (mLruHistory) {\n            return mLruHistory.get(binder);\n        }\n    }\n\n    final void addPendingIntent(final IBinder binder, String creator) {\n        synchronized (mLruHistory) {\n            try {\n                binder.linkToDeath(new IBinder.DeathRecipient() {\n                    @Override\n                    public void binderDied() {\n                        binder.unlinkToDeath(this, 0);\n                        mLruHistory.remove(binder);\n                    }\n                }, 0);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            PendingIntentData pendingIntentData = mLruHistory.get(binder);\n            if (pendingIntentData == null) {\n                mLruHistory.put(binder, new PendingIntentData(creator, binder));\n            } else {\n                pendingIntentData.creator = creator;\n            }\n        }\n    }\n\n    final void removePendingIntent(IBinder binder) {\n        synchronized (mLruHistory) {\n            mLruHistory.remove(binder);\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ProcessMap.java",
    "content": "package com.lody.virtual.server.am;\n\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.helper.collection.SparseArray;\n\nclass ProcessMap<E> {\n\tprivate final ArrayMap<String, SparseArray<E>> mMap = new ArrayMap<>();\n\n\tpublic E get(String name, int uid) {\n\t\tSparseArray<E> uids = mMap.get(name);\n\t\tif (uids == null)\n\t\t\treturn null;\n\t\treturn uids.get(uid);\n\t}\n\n\tpublic E put(String name, int uid, E value) {\n\t\tSparseArray<E> uids = mMap.get(name);\n\t\tif (uids == null) {\n\t\t\tuids = new SparseArray<E>(2);\n\t\t\tmMap.put(name, uids);\n\t\t}\n\t\tuids.put(uid, value);\n\t\treturn value;\n\t}\n\n\tpublic E remove(String name, int uid) {\n\t\tSparseArray<E> uids = mMap.get(name);\n\t\tif (uids != null) {\n\t\t\tfinal E old = uids.removeReturnOld(uid);\n\t\t\tif (uids.size() == 0) {\n\t\t\t\tmMap.remove(name);\n\t\t\t}\n\t\t\treturn old;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic ArrayMap<String, SparseArray<E>> getMap() {\n\t\treturn mMap;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ProcessRecord.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.content.pm.ApplicationInfo;\nimport android.os.Binder;\nimport android.os.ConditionVariable;\nimport android.os.IInterface;\n\nimport com.lody.virtual.client.IVClient;\nimport com.lody.virtual.os.VUserHandle;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nfinal class ProcessRecord extends Binder implements Comparable<ProcessRecord> {\n\n\tfinal ConditionVariable lock = new ConditionVariable();\n\tpublic final ApplicationInfo info; // all about the first app in the process\n\tfinal public String processName; // name of the process\n\tfinal Set<String> pkgList = new HashSet<>(); // List of packages\n\tpublic IVClient client;\n\tIInterface appThread;\n\tpublic int pid;\n\tpublic int vuid;\n\tpublic int vpid;\n\tpublic int userId;\n\tboolean doneExecuting;\n    int priority;\n\n\tpublic ProcessRecord(ApplicationInfo info, String processName, int vuid, int vpid) {\n\t\tthis.info = info;\n\t\tthis.vuid = vuid;\n\t\tthis.vpid = vpid;\n\t\tthis.userId = VUserHandle.getUserId(vuid);\n\t\tthis.processName = processName;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif (this == o)\n\t\t\treturn true;\n\t\tif (o == null || getClass() != o.getClass())\n\t\t\treturn false;\n\t\tProcessRecord record = (ProcessRecord) o;\n\t\treturn processName != null ? processName.equals(record.processName) : record.processName == null;\n\t}\n\n    @Override\n    public int compareTo(ProcessRecord another) {\n        return this.priority - another.priority;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/ServiceRecord.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.app.IServiceConnection;\nimport android.app.Notification;\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\npublic class ServiceRecord extends Binder {\n\tpublic final List<IntentBindRecord> bindings = new ArrayList<>();\n\tpublic long activeSince;\n\tpublic long lastActivityTime;\n\tpublic ServiceInfo serviceInfo;\n\tpublic int startId;\n\tpublic ProcessRecord process;\n\tpublic int foregroundId;\n\tpublic Notification foregroundNoti;\n\n\tpublic boolean containConnection(IServiceConnection connection) {\n\t\tfor (IntentBindRecord record : bindings) {\n\t\t\tif (record.containConnection(connection)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic int getClientCount() {\n\t\treturn bindings.size();\n\t}\n\n\n\tint getConnectionCount() {\n\t\tint count = 0;\n\t\tsynchronized (bindings) {\n\t\t\tfor (IntentBindRecord record : bindings) {\n\t\t\t\tcount += record.connections.size();\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\n\tIntentBindRecord peekBinding(Intent service) {\n\t\tsynchronized (bindings) {\n\t\t\tfor (IntentBindRecord bindRecord : bindings) {\n\t\t\t\tif (bindRecord.intent.filterEquals(service)) {\n\t\t\t\t\treturn bindRecord;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tvoid addToBoundIntent(Intent intent, IServiceConnection connection) {\n\t\tIntentBindRecord record = peekBinding(intent);\n\t\tif (record == null) {\n\t\t\trecord = new IntentBindRecord();\n\t\t\trecord.intent = intent;\n\t\t\tsynchronized (bindings) {\n\t\t\t\tbindings.add(record);\n\t\t\t}\n\t\t}\n\t\trecord.addConnection(connection);\n\t}\n\n\tpublic static class IntentBindRecord {\n\t\tpublic  final List<IServiceConnection> connections = Collections.synchronizedList(new ArrayList<IServiceConnection>());\n\t\tpublic IBinder binder;\n\t\tIntent intent;\n\t\tpublic boolean doRebind = false;\n\n\t\tpublic boolean containConnection(IServiceConnection connection) {\n\t\t\tfor (IServiceConnection con : connections) {\n\t\t\t\tif (con.asBinder() == connection.asBinder()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic void addConnection(IServiceConnection connection) {\n\t\t\tif (!containConnection(connection)) {\n\t\t\t\tconnections.add(connection);\n\t\t\t\ttry {\n\t\t\t\t\tconnection.asBinder().linkToDeath(new DeathRecipient(this, connection), 0);\n\t\t\t\t} catch (RemoteException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void removeConnection(IServiceConnection connection) {\n\t\t\tsynchronized (connections) {\n\t\t\t\tIterator<IServiceConnection> iterator = connections.iterator();\n\t\t\t\twhile (iterator.hasNext()) {\n\t\t\t\t\tIServiceConnection conn = iterator.next();\n\t\t\t\t\tif (conn.asBinder() == connection.asBinder()) {\n\t\t\t\t\t\titerator.remove();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static class DeathRecipient implements IBinder.DeathRecipient {\n\n\t\tprivate final IntentBindRecord bindRecord;\n\t\tprivate final IServiceConnection connection;\n\n\t\tprivate DeathRecipient(IntentBindRecord bindRecord, IServiceConnection connection) {\n\t\t\tthis.bindRecord = bindRecord;\n\t\t\tthis.connection = connection;\n\t\t}\n\n\t\t@Override\n\t\tpublic void binderDied() {\n\t\t\tbindRecord.removeConnection(connection);\n\t\t\tconnection.asBinder().unlinkToDeath(this, 0);\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/TaskRecord.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\n\nimport com.lody.virtual.remote.AppTaskInfo;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * @author Lody\n */\n\nclass TaskRecord {\n    public final List<ActivityRecord> activities = Collections.synchronizedList(new ArrayList<ActivityRecord>());\n    public int taskId;\n    public int userId;\n    public String affinity;\n    public Intent taskRoot;\n\n    TaskRecord(int taskId, int userId, String affinity, Intent intent) {\n        this.taskId = taskId;\n        this.userId = userId;\n        this.affinity = affinity;\n        this.taskRoot = intent;\n    }\n\n    AppTaskInfo getAppTaskInfo() {\n        int len = activities.size();\n        if (len <= 0) {\n            return null;\n        }\n        ComponentName top = activities.get(len - 1).component;\n        return new AppTaskInfo(taskId, taskRoot, taskRoot.getComponent(), top);\n    }\n\n    public boolean isFinishing() {\n        boolean allFinish = true;\n        for (ActivityRecord r : activities) {\n            if (!r.marked) allFinish = false;\n        }\n        return allFinish;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/UidSystem.java",
    "content": "package com.lody.virtual.server.am;\n\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static android.os.Process.FIRST_APPLICATION_UID;\n\n/**\n * @author Lody\n */\n\npublic class UidSystem {\n\n    private static final String TAG = UidSystem.class.getSimpleName();\n\n    private final HashMap<String, Integer> mSharedUserIdMap = new HashMap<>();\n    private int mFreeUid = FIRST_APPLICATION_UID;\n\n\n    public void initUidList() {\n        mSharedUserIdMap.clear();\n        File uidFile = VEnvironment.getUidListFile();\n        if (!loadUidList(uidFile)) {\n            File bakUidFile = VEnvironment.getBakUidListFile();\n            loadUidList(bakUidFile);\n        }\n    }\n\n    private boolean loadUidList(File uidFile) {\n        if (!uidFile.exists()) {\n            return false;\n        }\n        try {\n            ObjectInputStream is = new ObjectInputStream(new FileInputStream(uidFile));\n            mFreeUid = is.readInt();\n            //noinspection unchecked\n            Map<String, Integer> map = (HashMap<String, Integer>) is.readObject();\n            mSharedUserIdMap.putAll(map);\n            is.close();\n        } catch (Throwable e) {\n            return false;\n        }\n        return true;\n    }\n\n    private void save() {\n        File uidFile = VEnvironment.getUidListFile();\n        File bakUidFile = VEnvironment.getBakUidListFile();\n        if (uidFile.exists()) {\n            if (bakUidFile.exists() && !bakUidFile.delete()) {\n                VLog.w(TAG, \"Warning: Unable to delete the expired file --\\n \" + bakUidFile.getPath());\n            }\n            try {\n                FileUtils.copyFile(uidFile, bakUidFile);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        try {\n            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(uidFile));\n            os.writeInt(mFreeUid);\n            os.writeObject(mSharedUserIdMap);\n            os.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public int getOrCreateUid(VPackage pkg) {\n        String sharedUserId = pkg.mSharedUserId;\n        if (sharedUserId == null) {\n            sharedUserId = pkg.packageName;\n        }\n        Integer uid = mSharedUserIdMap.get(sharedUserId);\n        if (uid != null) {\n            return uid;\n        }\n        int newUid = ++mFreeUid;\n        mSharedUserIdMap.put(sharedUserId, newUid);\n        save();\n        return newUid;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java",
    "content": "package com.lody.virtual.server.am;\n\nimport android.app.ActivityManager;\nimport android.app.IServiceConnection;\nimport android.app.IStopUserCallback;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\n\nimport com.lody.virtual.client.IVClient;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.env.SpecialComponentList;\nimport com.lody.virtual.client.ipc.ProviderCall;\nimport com.lody.virtual.client.ipc.VNotificationManager;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.helper.collection.SparseArray;\nimport com.lody.virtual.helper.compat.ActivityManagerCompat;\nimport com.lody.virtual.helper.compat.ApplicationThreadCompat;\nimport com.lody.virtual.helper.compat.BundleCompat;\nimport com.lody.virtual.helper.compat.IApplicationThreadCompat;\nimport com.lody.virtual.helper.utils.ComponentUtils;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VBinder;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.AppTaskInfo;\nimport com.lody.virtual.remote.BadgerInfo;\nimport com.lody.virtual.remote.PendingIntentData;\nimport com.lody.virtual.remote.PendingResultData;\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.server.IActivityManager;\nimport com.lody.virtual.server.interfaces.IProcessObserver;\nimport com.lody.virtual.server.pm.PackageCacheManager;\nimport com.lody.virtual.server.pm.PackageSetting;\nimport com.lody.virtual.server.pm.VAppManagerService;\nimport com.lody.virtual.server.pm.VPackageManagerService;\nimport com.lody.virtual.server.secondary.BinderDelegateService;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport mirror.android.app.IServiceConnectionO;\n\nimport static android.os.Process.killProcess;\nimport static com.lody.virtual.os.VUserHandle.getUserId;\n\n/**\n * @author Lody\n */\npublic class VActivityManagerService extends IActivityManager.Stub {\n\n    private static final boolean BROADCAST_NOT_STARTED_PKG = false;\n\n    private static final AtomicReference<VActivityManagerService> sService = new AtomicReference<>();\n    private static final String TAG = VActivityManagerService.class.getSimpleName();\n    private final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();\n    private final ActivityStack mMainStack = new ActivityStack(this);\n    private final Set<ServiceRecord> mHistory = new HashSet<ServiceRecord>();\n    private final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();\n    private final PendingIntents mPendingIntents = new PendingIntents();\n    private ActivityManager am = (ActivityManager) VirtualCore.get().getContext()\n            .getSystemService(Context.ACTIVITY_SERVICE);\n    private NotificationManager nm = (NotificationManager) VirtualCore.get().getContext()\n            .getSystemService(Context.NOTIFICATION_SERVICE);\n\n    public static VActivityManagerService get() {\n        return sService.get();\n    }\n\n    public static void systemReady(Context context) {\n        new VActivityManagerService().onCreate(context);\n    }\n\n    private static ServiceInfo resolveServiceInfo(Intent service, int userId) {\n        if (service != null) {\n            ServiceInfo serviceInfo = VirtualCore.get().resolveServiceInfo(service, userId);\n            if (serviceInfo != null) {\n                return serviceInfo;\n            }\n        }\n        return null;\n    }\n\n    public void onCreate(Context context) {\n        AttributeCache.init(context);\n        PackageManager pm = context.getPackageManager();\n        PackageInfo packageInfo = null;\n        try {\n            packageInfo = pm.getPackageInfo(context.getPackageName(),\n                    PackageManager.GET_ACTIVITIES | PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA);\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n        }\n\n        if (packageInfo == null) {\n            throw new RuntimeException(\"Unable to found PackageInfo : \" + context.getPackageName());\n        }\n        sService.set(this);\n\n    }\n\n\n    @Override\n    public int startActivity(Intent intent, ActivityInfo info, IBinder resultTo, Bundle options, String resultWho, int requestCode, int userId) {\n        synchronized (this) {\n            return mMainStack.startActivityLocked(userId, intent, info, resultTo, options, resultWho, requestCode);\n        }\n    }\n\n    @Override\n    public int startActivities(Intent[] intents, String[] resolvedTypes, IBinder token, Bundle options, int userId) {\n        synchronized (this) {\n            ActivityInfo[] infos = new ActivityInfo[intents.length];\n            for (int i = 0; i < intents.length; i++) {\n                ActivityInfo ai = VirtualCore.get().resolveActivityInfo(intents[i], userId);\n                if (ai == null) {\n                    return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;\n                }\n                infos[i] = ai;\n\n            }\n            return mMainStack.startActivitiesLocked(userId, intents, infos, resolvedTypes, token, options);\n        }\n    }\n\n    @Override\n    public String getPackageForIntentSender(IBinder binder) {\n        PendingIntentData data = mPendingIntents.getPendingIntent(binder);\n        if (data != null) {\n            return data.creator;\n        }\n        return null;\n    }\n\n\n    @Override\n    public PendingIntentData getPendingIntent(IBinder binder) {\n        return mPendingIntents.getPendingIntent(binder);\n    }\n\n    @Override\n    public void addPendingIntent(IBinder binder, String creator) {\n        mPendingIntents.addPendingIntent(binder, creator);\n    }\n\n    @Override\n    public void removePendingIntent(IBinder binder) {\n        mPendingIntents.removePendingIntent(binder);\n    }\n\n    @Override\n    public int getSystemPid() {\n        return VirtualCore.get().myUid();\n    }\n\n    @Override\n    public void onActivityCreated(ComponentName component, ComponentName caller, IBinder token, Intent intent, String affinity, int taskId, int launchMode, int flags) {\n        int pid = Binder.getCallingPid();\n        ProcessRecord targetApp = findProcessLocked(pid);\n        if (targetApp != null) {\n            mMainStack.onActivityCreated(targetApp, component, caller, token, intent, affinity, taskId, launchMode, flags);\n        }\n    }\n\n    @Override\n    public void onActivityResumed(int userId, IBinder token) {\n        mMainStack.onActivityResumed(userId, token);\n    }\n\n    @Override\n    public boolean onActivityDestroyed(int userId, IBinder token) {\n        ActivityRecord r = mMainStack.onActivityDestroyed(userId, token);\n        return r != null;\n    }\n\n    @Override\n    public AppTaskInfo getTaskInfo(int taskId) {\n        return mMainStack.getTaskInfo(taskId);\n    }\n\n    @Override\n    public String getPackageForToken(int userId, IBinder token) {\n        return mMainStack.getPackageForToken(userId, token);\n    }\n\n    @Override\n    public ComponentName getActivityClassForToken(int userId, IBinder token) {\n        return mMainStack.getActivityClassForToken(userId, token);\n    }\n\n\n    private void processDead(ProcessRecord record) {\n        synchronized (mHistory) {\n            Iterator<ServiceRecord> iterator = mHistory.iterator();\n            while (iterator.hasNext()) {\n                ServiceRecord r = iterator.next();\n                if (r.process != null && r.process.pid == record.pid) {\n                    iterator.remove();\n                }\n            }\n            mMainStack.processDied(record);\n        }\n    }\n\n\n    @Override\n    public IBinder acquireProviderClient(int userId, ProviderInfo info) {\n        ProcessRecord callerApp;\n        synchronized (mPidsSelfLocked) {\n            callerApp = findProcessLocked(VBinder.getCallingPid());\n        }\n        if (callerApp == null) {\n            throw new SecurityException(\"Who are you?\");\n        }\n        String processName = info.processName;\n        ProcessRecord r;\n        synchronized (this) {\n            r = startProcessIfNeedLocked(processName, userId, info.packageName);\n        }\n        if (r != null && r.client.asBinder().pingBinder()) {\n            try {\n                return r.client.acquireProviderClient(info);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ComponentName getCallingActivity(int userId, IBinder token) {\n        return mMainStack.getCallingActivity(userId, token);\n    }\n\n    @Override\n    public String getCallingPackage(int userId, IBinder token) {\n        return mMainStack.getCallingPackage(userId, token);\n    }\n\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        try {\n            return super.onTransact(code, data, reply, flags);\n        } catch (Throwable e) {\n            e.printStackTrace();\n            throw e;\n        }\n    }\n\n    private void addRecord(ServiceRecord r) {\n        mHistory.add(r);\n    }\n\n    private ServiceRecord findRecordLocked(int userId, ServiceInfo serviceInfo) {\n        synchronized (mHistory) {\n            for (ServiceRecord r : mHistory) {\n                // If service is not created, and bindService with the flag that is\n                // not BIND_AUTO_CREATE, r.process is null\n                if ((r.process == null || r.process.userId == userId)\n                        && ComponentUtils.isSameComponent(serviceInfo, r.serviceInfo)) {\n                    return r;\n                }\n            }\n            return null;\n        }\n    }\n\n    private ServiceRecord findRecordLocked(IServiceConnection connection) {\n        synchronized (mHistory) {\n            for (ServiceRecord r : mHistory) {\n                if (r.containConnection(connection)) {\n                    return r;\n                }\n            }\n            return null;\n        }\n    }\n\n\n    @Override\n    public ComponentName startService(IBinder caller, Intent service, String resolvedType, int userId) {\n        synchronized (this) {\n            return startServiceCommon(service, true, userId);\n        }\n    }\n\n    private ComponentName startServiceCommon(Intent service,\n                                             boolean scheduleServiceArgs, int userId) {\n        ServiceInfo serviceInfo = resolveServiceInfo(service, userId);\n        if (serviceInfo == null) {\n            return null;\n        }\n        ProcessRecord targetApp = startProcessIfNeedLocked(ComponentUtils.getProcessName(serviceInfo),\n                userId,\n                serviceInfo.packageName);\n\n        if (targetApp == null) {\n            VLog.e(TAG, \"Unable to start new Process for : \" + ComponentUtils.toComponentName(serviceInfo));\n            return null;\n        }\n        IInterface appThread = targetApp.appThread;\n        ServiceRecord r = findRecordLocked(userId, serviceInfo);\n        if (r == null) {\n            r = new ServiceRecord();\n            r.startId = 0;\n            r.activeSince = SystemClock.elapsedRealtime();\n            r.process = targetApp;\n            r.serviceInfo = serviceInfo;\n            try {\n                IApplicationThreadCompat.scheduleCreateService(appThread, r, r.serviceInfo, 0);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n            addRecord(r);\n        }\n        r.lastActivityTime = SystemClock.uptimeMillis();\n        if (scheduleServiceArgs) {\n            r.startId++;\n            boolean taskRemoved = serviceInfo.applicationInfo != null\n                    && serviceInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.ECLAIR;\n            try {\n                IApplicationThreadCompat.scheduleServiceArgs(appThread, r, taskRemoved, r.startId, 0, service);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        return ComponentUtils.toComponentName(serviceInfo);\n    }\n\n    @Override\n    public int stopService(IBinder caller, Intent service, String resolvedType, int userId) {\n        synchronized (this) {\n            ServiceInfo serviceInfo = resolveServiceInfo(service, userId);\n            if (serviceInfo == null) {\n                return 0;\n            }\n            ServiceRecord r = findRecordLocked(userId, serviceInfo);\n            if (r == null) {\n                return 0;\n            }\n            stopServiceCommon(r, ComponentUtils.toComponentName(serviceInfo));\n            return 1;\n        }\n    }\n\n    @Override\n    public boolean stopServiceToken(ComponentName className, IBinder token, int startId, int userId) {\n        synchronized (this) {\n            ServiceRecord r = (ServiceRecord) token;\n            if (r != null && (r.startId == startId || startId == -1)) {\n                stopServiceCommon(r, className);\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n    private void stopServiceCommon(ServiceRecord r, ComponentName className) {\n        for (ServiceRecord.IntentBindRecord bindRecord : r.bindings) {\n            for (IServiceConnection connection : bindRecord.connections) {\n                // Report to all of the connections that the service is no longer\n                // available.\n                try {\n                    if(Build.VERSION.SDK_INT >= 26) {\n                        IServiceConnectionO.connected.call(connection, className, null, true);\n                    } else {\n                        connection.connected(className, null);\n                    }\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n            try {\n                IApplicationThreadCompat.scheduleUnbindService(r.process.appThread, r, bindRecord.intent);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        try {\n            IApplicationThreadCompat.scheduleStopService(r.process.appThread, r);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n        mHistory.remove(r);\n\n    }\n\n    @Override\n    public int bindService(IBinder caller, IBinder token, Intent service, String resolvedType,\n                           IServiceConnection connection, int flags, int userId) {\n        synchronized (this) {\n            ServiceInfo serviceInfo = resolveServiceInfo(service, userId);\n            if (serviceInfo == null) {\n                return 0;\n            }\n            ServiceRecord r = findRecordLocked(userId, serviceInfo);\n            boolean firstLaunch = r == null;\n            if (firstLaunch) {\n                if ((flags & Context.BIND_AUTO_CREATE) != 0) {\n                    startServiceCommon(service, false, userId);\n                    r = findRecordLocked(userId, serviceInfo);\n                }\n            }\n            if (r == null) {\n                return 0;\n            }\n            ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service);\n\n            if (boundRecord != null && boundRecord.binder != null && boundRecord.binder.pingBinder()) {\n                if (boundRecord.doRebind) {\n                    try {\n                        IApplicationThreadCompat.scheduleBindService(r.process.appThread, r, service, true, 0);\n                    } catch (RemoteException e) {\n                        e.printStackTrace();\n                    }\n                }\n                ComponentName componentName = new ComponentName(r.serviceInfo.packageName, r.serviceInfo.name);\n                connectService(connection, componentName, boundRecord, false);\n            } else {\n                try {\n                    IApplicationThreadCompat.scheduleBindService(r.process.appThread, r, service, false, 0);\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n            r.lastActivityTime = SystemClock.uptimeMillis();\n            r.addToBoundIntent(service, connection);\n            return 1;\n        }\n    }\n\n\n    @Override\n    public boolean unbindService(IServiceConnection connection, int userId) {\n        synchronized (this) {\n            ServiceRecord r = findRecordLocked(connection);\n            if (r == null) {\n                return false;\n            }\n\n            for (ServiceRecord.IntentBindRecord bindRecord : r.bindings) {\n                if (!bindRecord.containConnection(connection)) {\n                    continue;\n                }\n                bindRecord.removeConnection(connection);\n                try {\n                    IApplicationThreadCompat.scheduleUnbindService(r.process.appThread, r, bindRecord.intent);\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            }\n\n            if (r.startId <= 0 && r.getConnectionCount() <= 0) {\n                try {\n                    IApplicationThreadCompat.scheduleStopService(r.process.appThread, r);\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {\n                    mHistory.remove(r);\n                }\n            }\n            return true;\n        }\n    }\n\n    @Override\n    public void unbindFinished(IBinder token, Intent service, boolean doRebind, int userId) {\n        synchronized (this) {\n            ServiceRecord r = (ServiceRecord) token;\n            if (r != null) {\n                ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service);\n                if (boundRecord != null) {\n                    boundRecord.doRebind = doRebind;\n                }\n            }\n        }\n    }\n\n\n    @Override\n    public boolean isVAServiceToken(IBinder token) {\n        return token instanceof ServiceRecord;\n    }\n\n\n    @Override\n    public void serviceDoneExecuting(IBinder token, int type, int startId, int res, int userId) {\n        synchronized (this) {\n            ServiceRecord r = (ServiceRecord) token;\n            if (r == null) {\n                return;\n            }\n            if (ActivityManagerCompat.SERVICE_DONE_EXECUTING_STOP == type) {\n                mHistory.remove(r);\n            }\n        }\n    }\n\n    @Override\n    public IBinder peekService(Intent service, String resolvedType, int userId) {\n        synchronized (this) {\n            ServiceInfo serviceInfo = resolveServiceInfo(service, userId);\n            if (serviceInfo == null) {\n                return null;\n            }\n            ServiceRecord r = findRecordLocked(userId, serviceInfo);\n            if (r != null) {\n                ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service);\n                if (boundRecord != null) {\n                    return boundRecord.binder;\n                }\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public void publishService(IBinder token, Intent intent, IBinder service, int userId) {\n        synchronized (this) {\n            ServiceRecord r = (ServiceRecord) token;\n            if (r != null) {\n                ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(intent);\n                if (boundRecord != null) {\n                    boundRecord.binder = service;\n                    for (IServiceConnection conn : boundRecord.connections) {\n                        ComponentName component = ComponentUtils.toComponentName(r.serviceInfo);\n                        connectService(conn, component, boundRecord, false);\n                    }\n                }\n            }\n        }\n    }\n\n    private void connectService(IServiceConnection conn, ComponentName component, ServiceRecord.IntentBindRecord r,boolean dead) {\n        try {\n            BinderDelegateService delegateService = new BinderDelegateService(component, r.binder);\n            if (Build.VERSION.SDK_INT >= 26) {\n                IServiceConnectionO.connected.call(conn, component, delegateService, dead);\n            } else {\n                conn.connected(component, delegateService);\n            }\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public VParceledListSlice<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags, int userId) {\n        synchronized (mHistory) {\n            List<ActivityManager.RunningServiceInfo> services = new ArrayList<>(mHistory.size());\n            for (ServiceRecord r : mHistory) {\n                if (r.process.userId != userId) {\n                    continue;\n                }\n                ActivityManager.RunningServiceInfo info = new ActivityManager.RunningServiceInfo();\n                info.uid = r.process.vuid;\n                info.pid = r.process.pid;\n                ProcessRecord processRecord = findProcessLocked(r.process.pid);\n                if (processRecord != null) {\n                    info.process = processRecord.processName;\n                    info.clientPackage = processRecord.info.packageName;\n                }\n                info.activeSince = r.activeSince;\n                info.lastActivityTime = r.lastActivityTime;\n                info.clientCount = r.getClientCount();\n                info.service = ComponentUtils.toComponentName(r.serviceInfo);\n                info.started = r.startId > 0;\n                services.add(info);\n            }\n            return new VParceledListSlice<>(services);\n        }\n    }\n\n    @Override\n    public void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification,\n                                     boolean removeNotification, int userId) {\n        ServiceRecord r = (ServiceRecord) token;\n        if (r != null) {\n            if (id != 0) {\n                if (notification == null) {\n                    throw new IllegalArgumentException(\"null notification\");\n                }\n                if (r.foregroundId != id) {\n                    if (r.foregroundId != 0) {\n                        cancelNotification(userId, r.foregroundId, r.serviceInfo.packageName);\n                    }\n                    r.foregroundId = id;\n                }\n                r.foregroundNoti = notification;\n                postNotification(userId, id, r.serviceInfo.packageName, notification);\n            } else {\n                if (removeNotification) {\n                    cancelNotification(userId, r.foregroundId, r.serviceInfo.packageName);\n                    r.foregroundId = 0;\n                    r.foregroundNoti = null;\n                }\n            }\n        }\n    }\n\n    private void cancelNotification(int userId, int id, String pkg) {\n        id = VNotificationManager.get().dealNotificationId(id, pkg, null, userId);\n        String tag = VNotificationManager.get().dealNotificationTag(id, pkg, null, userId);\n        nm.cancel(tag, id);\n    }\n\n    private void postNotification(int userId, int id, String pkg, Notification notification) {\n        id = VNotificationManager.get().dealNotificationId(id, pkg, null, userId);\n        String tag = VNotificationManager.get().dealNotificationTag(id, pkg, null, userId);\n//        VNotificationManager.get().dealNotification(id, notification, pkg);\n        VNotificationManager.get().addNotification(id, tag, pkg, userId);\n        try {\n            nm.notify(tag, id, notification);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void processRestarted(String packageName, String processName, int userId) {\n        int callingPid = getCallingPid();\n        int appId = VAppManagerService.get().getAppId(packageName);\n        int uid = VUserHandle.getUid(userId, appId);\n        synchronized (this) {\n            ProcessRecord app = findProcessLocked(callingPid);\n            if (app == null) {\n                ApplicationInfo appInfo = VPackageManagerService.get().getApplicationInfo(packageName, 0, userId);\n                appInfo.flags |= ApplicationInfo.FLAG_HAS_CODE;\n                String stubProcessName = getProcessName(callingPid);\n                int vpid = parseVPid(stubProcessName);\n                if (vpid != -1) {\n                    performStartProcessLocked(uid, vpid, appInfo, processName);\n                }\n            }\n        }\n    }\n\n    private int parseVPid(String stubProcessName) {\n        String prefix = VirtualCore.get().getHostPkg() + \":p\";\n        if (stubProcessName != null && stubProcessName.startsWith(prefix)) {\n            try {\n                return Integer.parseInt(stubProcessName.substring(prefix.length()));\n            } catch (NumberFormatException e) {\n                // ignore\n            }\n        }\n        return -1;\n    }\n\n\n    private String getProcessName(int pid) {\n        for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {\n            if (info.pid == pid) {\n                return info.processName;\n            }\n        }\n        return null;\n    }\n\n\n    private void attachClient(int pid, final IBinder clientBinder) {\n        final IVClient client = IVClient.Stub.asInterface(clientBinder);\n        if (client == null) {\n            killProcess(pid);\n            return;\n        }\n        IInterface thread = null;\n        try {\n            thread = ApplicationThreadCompat.asInterface(client.getAppThread());\n        } catch (RemoteException e) {\n            // process has dead\n        }\n        if (thread == null) {\n            killProcess(pid);\n            return;\n        }\n        ProcessRecord app = null;\n        try {\n            IBinder token = client.getToken();\n            if (token instanceof ProcessRecord) {\n                app = (ProcessRecord) token;\n            }\n        } catch (RemoteException e) {\n            // process has dead\n        }\n        if (app == null) {\n            killProcess(pid);\n            return;\n        }\n        try {\n            final ProcessRecord record = app;\n            clientBinder.linkToDeath(new DeathRecipient() {\n                @Override\n                public void binderDied() {\n                    clientBinder.unlinkToDeath(this, 0);\n                    onProcessDead(record);\n                }\n            }, 0);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n        app.client = client;\n        app.appThread = thread;\n        app.pid = pid;\n        synchronized (mProcessNames) {\n            mProcessNames.put(app.processName, app.vuid, app);\n            mPidsSelfLocked.put(app.pid, app);\n        }\n    }\n\n    private void onProcessDead(ProcessRecord record) {\n        mProcessNames.remove(record.processName, record.vuid);\n        mPidsSelfLocked.remove(record.pid);\n        processDead(record);\n        record.lock.open();\n    }\n\n    @Override\n    public int getFreeStubCount() {\n        return VASettings.STUB_COUNT - mPidsSelfLocked.size();\n    }\n\n    @Override\n    public int initProcess(String packageName, String processName, int userId) {\n        synchronized (this) {\n            ProcessRecord r = startProcessIfNeedLocked(processName, userId, packageName);\n            return r != null ? r.vpid : -1;\n        }\n    }\n\n    ProcessRecord startProcessIfNeedLocked(String processName, int userId, String packageName) {\n        if (VActivityManagerService.get().getFreeStubCount() < 3) {\n            // run GC\n            killAllApps();\n        }\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        ApplicationInfo info = VPackageManagerService.get().getApplicationInfo(packageName, 0, userId);\n        if (ps == null || info == null) {\n            return null;\n        }\n        if (!ps.isLaunched(userId)) {\n            sendFirstLaunchBroadcast(ps, userId);\n            ps.setLaunched(userId, true);\n            VAppManagerService.get().savePersistenceData();\n        }\n        int uid = VUserHandle.getUid(userId, ps.appId);\n        ProcessRecord app = mProcessNames.get(processName, uid);\n        if (app != null && app.client.asBinder().pingBinder()) {\n            return app;\n        }\n        int vpid = queryFreeStubProcessLocked();\n        if (vpid == -1) {\n            return null;\n        }\n        app = performStartProcessLocked(uid, vpid, info, processName);\n        if (app != null) {\n            app.pkgList.add(info.packageName);\n        }\n        return app;\n    }\n\n    private void sendFirstLaunchBroadcast(PackageSetting ps, int userId) {\n        Intent intent = new Intent(Intent.ACTION_PACKAGE_FIRST_LAUNCH, Uri.fromParts(\"package\", ps.packageName, null));\n        intent.setPackage(ps.packageName);\n        intent.putExtra(Intent.EXTRA_UID, VUserHandle.getUid(ps.appId, userId));\n        intent.putExtra(\"android.intent.extra.user_handle\", userId);\n        sendBroadcastAsUser(intent, null);\n    }\n\n\n    @Override\n    public int getUidByPid(int pid) {\n        synchronized (mPidsSelfLocked) {\n            ProcessRecord r = findProcessLocked(pid);\n            if (r != null) {\n                return r.vuid;\n            }\n        }\n        return Process.myUid();\n    }\n\n    private ProcessRecord performStartProcessLocked(int vuid, int vpid, ApplicationInfo info, String processName) {\n        ProcessRecord app = new ProcessRecord(info, processName, vuid, vpid);\n        Bundle extras = new Bundle();\n        BundleCompat.putBinder(extras, \"_VA_|_binder_\", app);\n        extras.putInt(\"_VA_|_vuid_\", vuid);\n        extras.putString(\"_VA_|_process_\", processName);\n        extras.putString(\"_VA_|_pkg_\", info.packageName);\n        Bundle res = ProviderCall.call(VASettings.getStubAuthority(vpid), \"_VA_|_init_process_\", null, extras);\n        if (res == null) {\n            return null;\n        }\n        int pid = res.getInt(\"_VA_|_pid_\");\n        IBinder clientBinder = BundleCompat.getBinder(res, \"_VA_|_client_\");\n        attachClient(pid, clientBinder);\n        return app;\n    }\n\n    private int queryFreeStubProcessLocked() {\n        for (int vpid = 0; vpid < VASettings.STUB_COUNT; vpid++) {\n            int N = mPidsSelfLocked.size();\n            boolean using = false;\n            while (N-- > 0) {\n                ProcessRecord r = mPidsSelfLocked.valueAt(N);\n                if (r.vpid == vpid) {\n                    using = true;\n                    break;\n                }\n            }\n            if (using) {\n                continue;\n            }\n            return vpid;\n        }\n        return -1;\n    }\n\n    @Override\n    public boolean isAppProcess(String processName) {\n        return parseVPid(processName) != -1;\n    }\n\n    @Override\n    public boolean isAppPid(int pid) {\n        synchronized (mPidsSelfLocked) {\n            return findProcessLocked(pid) != null;\n        }\n    }\n\n    @Override\n    public String getAppProcessName(int pid) {\n        synchronized (mPidsSelfLocked) {\n            ProcessRecord r = mPidsSelfLocked.get(pid);\n            if (r != null) {\n                return r.processName;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<String> getProcessPkgList(int pid) {\n        synchronized (mPidsSelfLocked) {\n            ProcessRecord r = mPidsSelfLocked.get(pid);\n            if (r != null) {\n                return new ArrayList<>(r.pkgList);\n            }\n        }\n        return Collections.emptyList();\n    }\n\n    @Override\n    public void killAllApps() {\n        synchronized (mPidsSelfLocked) {\n            for (int i = 0; i < mPidsSelfLocked.size(); i++) {\n                ProcessRecord r = mPidsSelfLocked.valueAt(i);\n                killProcess(r.pid);\n            }\n        }\n    }\n\n    @Override\n    public void killAppByPkg(final String pkg, int userId) {\n        synchronized (mProcessNames) {\n            ArrayMap<String, SparseArray<ProcessRecord>> map = mProcessNames.getMap();\n            int N = map.size();\n            while (N-- > 0) {\n                SparseArray<ProcessRecord> uids = map.valueAt(N);\n                for (int i = 0; i < uids.size(); i++) {\n                    ProcessRecord r = uids.valueAt(i);\n                    if (userId != VUserHandle.USER_ALL) {\n                        if (r.userId != userId) {\n                            continue;\n                        }\n                    }\n                    if (r.pkgList.contains(pkg)) {\n                        killProcess(r.pid);\n                    }\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean isAppRunning(String packageName, int userId) {\n        boolean running = false;\n        synchronized (mPidsSelfLocked) {\n            int N = mPidsSelfLocked.size();\n            while (N-- > 0) {\n                ProcessRecord r = mPidsSelfLocked.valueAt(N);\n                if (r.userId == userId && r.info.packageName.equals(packageName)) {\n                    running = true;\n                    break;\n                }\n            }\n            return running;\n        }\n    }\n\n    @Override\n    public void killApplicationProcess(final String processName, int uid) {\n        synchronized (mProcessNames) {\n            ProcessRecord r = mProcessNames.get(processName, uid);\n            if (r != null) {\n                killProcess(r.pid);\n            }\n        }\n    }\n\n    @Override\n    public void dump() {\n\n    }\n\n    @Override\n    public void registerProcessObserver(IProcessObserver observer) {\n\n    }\n\n    @Override\n    public void unregisterProcessObserver(IProcessObserver observer) {\n\n    }\n\n    @Override\n    public String getInitialPackage(int pid) {\n        synchronized (mPidsSelfLocked) {\n            ProcessRecord r = mPidsSelfLocked.get(pid);\n            if (r != null) {\n                return r.info.packageName;\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public void handleApplicationCrash() {\n        // Nothing\n    }\n\n    @Override\n    public void appDoneExecuting() {\n        synchronized (mPidsSelfLocked) {\n            ProcessRecord r = mPidsSelfLocked.get(VBinder.getCallingPid());\n            if (r != null) {\n                r.doneExecuting = true;\n                r.lock.open();\n            }\n        }\n    }\n\n\n    /**\n     * Should guard by {@link VActivityManagerService#mPidsSelfLocked}\n     *\n     * @param pid pid\n     */\n    public ProcessRecord findProcessLocked(int pid) {\n        return mPidsSelfLocked.get(pid);\n    }\n\n    /**\n     * Should guard by {@link VActivityManagerService#mProcessNames}\n     *\n     * @param uid vuid\n     */\n    public ProcessRecord findProcessLocked(String processName, int uid) {\n        return mProcessNames.get(processName, uid);\n    }\n\n    public int stopUser(int userHandle, IStopUserCallback.Stub stub) {\n        synchronized (mPidsSelfLocked) {\n            int N = mPidsSelfLocked.size();\n            while (N-- > 0) {\n                ProcessRecord r = mPidsSelfLocked.valueAt(N);\n                if (r.userId == userHandle) {\n                    killProcess(r.pid);\n                }\n            }\n        }\n        try {\n            stub.userStopped(userHandle);\n        } catch (RemoteException e) {\n            e.printStackTrace();\n        }\n        return 0;\n    }\n\n    public void sendOrderedBroadcastAsUser(Intent intent, VUserHandle user, String receiverPermission,\n                                           BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,\n                                           String initialData, Bundle initialExtras) {\n        Context context = VirtualCore.get().getContext();\n        if (user != null) {\n            intent.putExtra(\"_VA_|_user_id_\", user.getIdentifier());\n        }\n        // TODO: checkPermission\n        context.sendOrderedBroadcast(intent, null/* permission */, resultReceiver, scheduler, initialCode, initialData,\n                initialExtras);\n    }\n\n    public void sendBroadcastAsUser(Intent intent, VUserHandle user) {\n        SpecialComponentList.protectIntent(intent);\n        Context context = VirtualCore.get().getContext();\n        if (user != null) {\n            intent.putExtra(\"_VA_|_user_id_\", user.getIdentifier());\n        }\n        context.sendBroadcast(intent);\n    }\n\n    public boolean bindServiceAsUser(Intent service, ServiceConnection connection, int flags, VUserHandle user) {\n        service = new Intent(service);\n        if (user != null) {\n            service.putExtra(\"_VA_|_user_id_\", user.getIdentifier());\n        }\n        return VirtualCore.get().getContext().bindService(service, connection, flags);\n    }\n\n    public void sendBroadcastAsUser(Intent intent, VUserHandle user, String permission) {\n        SpecialComponentList.protectIntent(intent);\n        Context context = VirtualCore.get().getContext();\n        if (user != null) {\n            intent.putExtra(\"_VA_|_user_id_\", user.getIdentifier());\n        }\n        // TODO: checkPermission\n        context.sendBroadcast(intent);\n    }\n\n    boolean handleStaticBroadcast(int appId, ActivityInfo info, Intent intent,\n                                  PendingResultData result) {\n        Intent realIntent = intent.getParcelableExtra(\"_VA_|_intent_\");\n        ComponentName component = intent.getParcelableExtra(\"_VA_|_component_\");\n        int userId = intent.getIntExtra(\"_VA_|_user_id_\", VUserHandle.USER_NULL);\n        if (realIntent == null) {\n            return false;\n        }\n        if (userId < 0) {\n            VLog.w(TAG, \"Sent a broadcast without userId \" + realIntent);\n            return false;\n        }\n        int vuid = VUserHandle.getUid(userId, appId);\n        return handleUserBroadcast(vuid, info, component, realIntent, result);\n    }\n\n    private boolean handleUserBroadcast(int vuid, ActivityInfo info, ComponentName component, Intent realIntent, PendingResultData result) {\n        if (component != null && !ComponentUtils.toComponentName(info).equals(component)) {\n            // Verify the component.\n            return false;\n        }\n        String originAction = SpecialComponentList.unprotectAction(realIntent.getAction());\n        if (originAction != null) {\n            // restore to origin action.\n            realIntent.setAction(originAction);\n        }\n        handleStaticBroadcastAsUser(vuid, info, realIntent, result);\n        return true;\n    }\n\n    private void handleStaticBroadcastAsUser(int vuid, ActivityInfo info, Intent intent,\n                                             PendingResultData result) {\n        synchronized (this) {\n            ProcessRecord r = findProcessLocked(info.processName, vuid);\n            if ((BROADCAST_NOT_STARTED_PKG || isStartProcessForBroadcast(info.processName, info.packageName))\n                    && r == null) {\n                r = startProcessIfNeedLocked(info.processName, getUserId(vuid), info.packageName);\n            }\n            if (r != null && r.appThread != null) {\n                performScheduleReceiver(r.client, vuid, info, intent,\n                        result);\n            }\n        }\n    }\n\n    private static boolean isStartProcessForBroadcast(String processName, String packageName) {\n        return Constants.PRIVILEGE_APP.contains(packageName);\n    }\n\n    private void performScheduleReceiver(IVClient client, int vuid, ActivityInfo info, Intent intent,\n                                         PendingResultData result) {\n\n        ComponentName componentName = ComponentUtils.toComponentName(info);\n        BroadcastSystem.get().broadcastSent(vuid, info, result);\n        try {\n            client.scheduleReceiver(info.processName, componentName, intent, result);\n        } catch (Throwable e) {\n            if (result != null) {\n                result.finish();\n            }\n        }\n    }\n\n    @Override\n    public void broadcastFinish(PendingResultData res) {\n        BroadcastSystem.get().broadcastFinish(res);\n    }\n\n    @Override\n    public void notifyBadgerChange(BadgerInfo info) throws RemoteException {\n        Intent intent = new Intent(VASettings.ACTION_BADGER_CHANGE);\n        intent.putExtra(\"userId\", info.userId);\n        intent.putExtra(\"packageName\", info.packageName);\n        intent.putExtra(\"badgerCount\", info.badgerCount);\n        VirtualCore.get().getContext().sendBroadcast(intent);\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/device/DeviceInfoPersistenceLayer.java",
    "content": "package com.lody.virtual.server.device;\n\nimport android.os.Parcel;\n\nimport com.lody.virtual.helper.PersistenceLayer;\nimport com.lody.virtual.helper.collection.SparseArray;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.remote.VDeviceInfo;\n\n/**\n * @author Lody\n */\n\npublic class DeviceInfoPersistenceLayer extends PersistenceLayer {\n\n    private VDeviceManagerService mService;\n\n    public DeviceInfoPersistenceLayer(VDeviceManagerService service) {\n        super(VEnvironment.getDeviceInfoFile());\n        this.mService = service;\n    }\n\n    @Override\n    public int getCurrentVersion() {\n        return 1;\n    }\n\n    @Override\n    public void writeMagic(Parcel p) {\n\n    }\n\n    @Override\n    public boolean verifyMagic(Parcel p) {\n        return true;\n    }\n\n    @Override\n    public void writePersistenceData(Parcel p) {\n        SparseArray<VDeviceInfo> infos = mService.getDeviceInfos();\n        int size = infos.size();\n        p.writeInt(size);\n        for (int i = 0; i < size; i++) {\n            int userId = infos.keyAt(i);\n            VDeviceInfo info = infos.valueAt(i);\n            p.writeInt(userId);\n            info.writeToParcel(p, 0);\n        }\n    }\n\n    @Override\n    public void readPersistenceData(Parcel p) {\n        SparseArray<VDeviceInfo> infos = mService.getDeviceInfos();\n        infos.clear();\n        int size = p.readInt();\n        while (size-- > 0) {\n            int userId = p.readInt();\n            VDeviceInfo info = new VDeviceInfo(p);\n            infos.put(userId, info);\n        }\n    }\n\n    @Override\n    public boolean onVersionConflict(int fileVersion, int currentVersion) {\n        return false;\n    }\n\n    @Override\n    public void onPersistenceFileDamage() {\n        getPersistenceFile().delete();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/device/VDeviceManagerService.java",
    "content": "package com.lody.virtual.server.device;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.provider.Settings;\nimport android.telephony.TelephonyManager;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.collection.SparseArray;\nimport com.lody.virtual.remote.VDeviceInfo;\nimport com.lody.virtual.server.IDeviceInfoManager;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\n/**\n * @author Lody\n */\n\npublic class VDeviceManagerService extends IDeviceInfoManager.Stub {\n\n    private static VDeviceManagerService sInstance = new VDeviceManagerService();\n    private final SparseArray<VDeviceInfo> mDeviceInfos = new SparseArray<>();\n    private DeviceInfoPersistenceLayer mPersistenceLayer = new DeviceInfoPersistenceLayer(this);\n    private UsedDeviceInfoPool mPool = new UsedDeviceInfoPool();\n\n    public static VDeviceManagerService get() {\n        return sInstance;\n    }\n\n    private final class UsedDeviceInfoPool {\n        List<String> deviceIds = new ArrayList<>();\n        List<String> androidIds = new ArrayList<>();\n        List<String> wifiMacs = new ArrayList<>();\n        List<String> bluetoothMacs = new ArrayList<>();\n        List<String> iccIds = new ArrayList<>();\n    }\n\n    public VDeviceManagerService() {\n        mPersistenceLayer.read();\n        for (int i = 0; i < mDeviceInfos.size(); i++) {\n            VDeviceInfo info = mDeviceInfos.valueAt(i);\n            addDeviceInfoToPool(info);\n        }\n    }\n\n    private void addDeviceInfoToPool(VDeviceInfo info) {\n        mPool.deviceIds.add(info.deviceId);\n        mPool.androidIds.add(info.androidId);\n        mPool.wifiMacs.add(info.wifiMac);\n        mPool.bluetoothMacs.add(info.bluetoothMac);\n        mPool.iccIds.add(info.iccId);\n    }\n\n    @Override\n    public VDeviceInfo getDeviceInfo(int userId) throws RemoteException {\n        VDeviceInfo info;\n        synchronized (mDeviceInfos) {\n            info = mDeviceInfos.get(userId);\n            if (info == null) {\n                info = generateDeviceInfo();\n                mDeviceInfos.put(userId, info);\n                mPersistenceLayer.save();\n            }\n        }\n        return info;\n    }\n\n    @Override\n    public void updateDeviceInfo(int userId, VDeviceInfo info) throws RemoteException {\n        synchronized (mDeviceInfos) {\n            if (info != null) {\n                mDeviceInfos.put(userId, info);\n                mPersistenceLayer.save();\n            }\n        }\n    }\n\n    private VDeviceInfo generateRandomDeviceInfo() {\n        VDeviceInfo info = new VDeviceInfo();\n        String value;\n        do {\n            value = generate10(15);\n            info.deviceId = value;\n        } while (mPool.deviceIds.contains(value));\n        do {\n            value = generate16(16);\n            info.androidId = value;\n        } while (mPool.androidIds.contains(value));\n        do {\n            value = generateMac();\n            info.wifiMac = value;\n        } while (mPool.wifiMacs.contains(value));\n        do {\n            value = generateMac();\n            info.bluetoothMac = value;\n        } while (mPool.bluetoothMacs.contains(value));\n\n        do {\n            value = generate10(20);\n            info.iccId = value;\n        } while (mPool.iccIds.contains(value));\n\n        info.serial = generateSerial();\n\n        addDeviceInfoToPool(info);\n        return info;\n    }\n\n    @SuppressLint(\"HardwareIds\")\n    private VDeviceInfo generateDeviceInfo() {\n        VDeviceInfo info = generateRandomDeviceInfo();\n        Context context = VirtualCore.get().getContext();\n        if (context == null) {\n            return info;\n        }\n\n        try {\n            String deviceId = null;\n            final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n            if (tm != null) {\n                deviceId = tm.getDeviceId();\n            }\n            if (deviceId != null) {\n                info.deviceId = deviceId;\n            }\n\n            String android_id = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);\n            if (android_id != null) {\n                info.androidId = android_id;\n            }\n\n            info.serial = Build.SERIAL;\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return info;\n    }\n\n    SparseArray<VDeviceInfo> getDeviceInfos() {\n        return mDeviceInfos;\n    }\n\n    private static String generate10(int length) {\n        Random random = new Random();\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < length; i++) {\n            sb.append(random.nextInt(10));\n        }\n        return sb.toString();\n    }\n\n    private static String generate16(int length) {\n        Random random = new Random();\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < length; i++) {\n            int nextInt = random.nextInt(16);\n            if (nextInt < 10) {\n                sb.append(nextInt);\n            } else {\n                sb.append((char) (nextInt + 87));\n            }\n        }\n        return sb.toString();\n    }\n\n    private static String generateMac() {\n        Random random = new Random();\n        StringBuilder sb = new StringBuilder();\n        int next = 1;\n        int cur = 0;\n        while (cur < 12) {\n            int val = random.nextInt(16);\n            if (val < 10) {\n                sb.append(val);\n            } else {\n                sb.append((char) (val + 87));\n            }\n            if (cur == next && cur != 11) {\n                sb.append(\":\");\n                next += 2;\n            }\n            cur++;\n        }\n        return sb.toString();\n    }\n\n    @SuppressLint(\"HardwareIds\")\n    private static String generateSerial() {\n        String serial;\n        if (Build.SERIAL == null || Build.SERIAL.length() <= 0) {\n            serial = \"0123456789ABCDEF\";\n        } else {\n            serial = Build.SERIAL;\n        }\n        List<Character> list = new ArrayList<>();\n        for (char c : serial.toCharArray()) {\n            list.add(c);\n        }\n        Collections.shuffle(list);\n        StringBuilder sb = new StringBuilder();\n        for (Character c : list) {\n            sb.append(c.charValue());\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/job/VJobSchedulerService.java",
    "content": "package com.lody.virtual.server.job;\n\nimport android.annotation.TargetApi;\nimport android.app.job.JobInfo;\nimport android.app.job.JobScheduler;\nimport android.app.job.JobWorkItem;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.PersistableBundle;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.ipc.VJobScheduler;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.utils.Singleton;\nimport com.lody.virtual.os.VBinder;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.server.IJobScheduler;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class VJobSchedulerService extends IJobScheduler.Stub {\n\n    private static final String TAG = VJobScheduler.class.getSimpleName();\n\n    private static final int JOB_FILE_VERSION = 1;\n    private final Map<JobId, JobConfig> mJobStore = new HashMap<>();\n    private int mGlobalJobId;\n\n    private final JobScheduler mScheduler = (JobScheduler)\n            VirtualCore.get().getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);\n\n    private final ComponentName mJobProxyComponent;\n\n    private VJobSchedulerService() {\n        mJobProxyComponent = new ComponentName(VirtualCore.get().getHostPkg(), VASettings.STUB_JOB);\n        readJobs();\n    }\n\n    private static final Singleton<VJobSchedulerService> gDefault = new Singleton<VJobSchedulerService>() {\n        @Override\n        protected VJobSchedulerService create() {\n            return new VJobSchedulerService();\n        }\n    };\n\n    public static VJobSchedulerService get() {\n        return gDefault.get();\n    }\n\n\n    public static final class JobId implements Parcelable {\n\n        public int vuid;\n        public String packageName;\n        /**\n         * The id given by User.\n         */\n        public int clientJobId;\n\n        JobId(int vuid, String packageName, int id) {\n            this.vuid = vuid;\n            this.packageName = packageName;\n            this.clientJobId = id;\n        }\n\n\n        JobId(Parcel in) {\n            this.vuid = in.readInt();\n            this.packageName = in.readString();\n            this.clientJobId = in.readInt();\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            JobId jobId = (JobId) o;\n\n            return vuid == jobId.vuid\n                    && clientJobId == jobId.clientJobId\n                    && TextUtils.equals(packageName, jobId.packageName);\n        }\n\n        @Override\n        public int hashCode() {\n            int result = vuid;\n            result = 31 * result + (packageName != null ? packageName.hashCode() : 0);\n            result = 31 * result + clientJobId;\n            return result;\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeInt(this.vuid);\n            dest.writeString(this.packageName);\n            dest.writeInt(this.clientJobId);\n        }\n\n        public static final Parcelable.Creator<JobId> CREATOR = new Parcelable.Creator<JobId>() {\n            @Override\n            public JobId createFromParcel(Parcel source) {\n                return new JobId(source);\n            }\n\n            @Override\n            public JobId[] newArray(int size) {\n                return new JobId[size];\n            }\n        };\n    }\n\n    public static final class JobConfig implements Parcelable {\n\n        /**\n         * The id given by VA.\n         */\n        public int virtualJobId;\n        public String serviceName;\n        public PersistableBundle extras;\n\n        JobConfig(int virtualJobId, String serviceName, PersistableBundle extra) {\n            this.virtualJobId = virtualJobId;\n            this.serviceName = serviceName;\n            this.extras = extra;\n        }\n\n        JobConfig(Parcel in) {\n            this.virtualJobId = in.readInt();\n            this.serviceName = in.readString();\n            this.extras = in.readParcelable(PersistableBundle.class.getClassLoader());\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeInt(this.virtualJobId);\n            dest.writeString(this.serviceName);\n            dest.writeParcelable(this.extras, flags);\n        }\n\n        public static final Parcelable.Creator<JobConfig> CREATOR = new Parcelable.Creator<JobConfig>() {\n            @Override\n            public JobConfig createFromParcel(Parcel source) {\n                return new JobConfig(source);\n            }\n\n            @Override\n            public JobConfig[] newArray(int size) {\n                return new JobConfig[size];\n            }\n        };\n    }\n\n\n    @Override\n    public int schedule(JobInfo job) throws RemoteException {\n        int vuid = VBinder.getCallingUid();\n        int id = job.getId();\n        ComponentName service = job.getService();\n        JobId jobId = new JobId(vuid, service.getPackageName(), id);\n        JobConfig config = mJobStore.get(jobId);\n        if (config == null) {\n            config = new JobConfig(mGlobalJobId++, service.getClassName(), job.getExtras());\n            mJobStore.put(jobId, config);\n        } else {\n            config.serviceName = service.getClassName();\n            config.extras = job.getExtras();\n        }\n        saveJobs();\n        mirror.android.app.job.JobInfo.jobId.set(job, config.virtualJobId);\n        mirror.android.app.job.JobInfo.service.set(job, mJobProxyComponent);\n        return mScheduler.schedule(job);\n    }\n\n    private void saveJobs() {\n        File jobFile = VEnvironment.getJobConfigFile();\n        Parcel p = Parcel.obtain();\n        try {\n            p.writeInt(JOB_FILE_VERSION);\n            p.writeInt(mJobStore.size());\n            for (Map.Entry<JobId, JobConfig> entry : mJobStore.entrySet()) {\n                entry.getKey().writeToParcel(p, 0);\n                entry.getValue().writeToParcel(p, 0);\n            }\n            FileOutputStream fos = new FileOutputStream(jobFile);\n            fos.write(p.marshall());\n            fos.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n    }\n\n    private void readJobs() {\n        File jobFile = VEnvironment.getJobConfigFile();\n        if (!jobFile.exists()) {\n            return;\n        }\n        Parcel p = Parcel.obtain();\n        try {\n            FileInputStream fis = new FileInputStream(jobFile);\n            byte[] bytes = new byte[(int) jobFile.length()];\n            int len = fis.read(bytes);\n            fis.close();\n            if (len != bytes.length) {\n                throw new IOException(\"Unable to read job config.\");\n            }\n            p.unmarshall(bytes, 0, bytes.length);\n            p.setDataPosition(0);\n            int version = p.readInt();\n            if (version != JOB_FILE_VERSION) {\n                throw new IOException(\"Bad version of job file: \" + version);\n            }\n            if (!mJobStore.isEmpty()) {\n                mJobStore.clear();\n            }\n            int count = p.readInt();\n            for (int i = 0; i < count; i++) {\n                JobId jobId = new JobId(p);\n                JobConfig config = new JobConfig(p);\n                mJobStore.put(jobId, config);\n                mGlobalJobId = Math.max(mGlobalJobId, config.virtualJobId);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n\n    }\n\n    @Override\n    public void cancel(int jobId) throws RemoteException {\n        int vuid = VBinder.getCallingUid();\n        synchronized (mJobStore) {\n            boolean changed = false;\n            Iterator<Map.Entry<JobId, JobConfig>> iterator = mJobStore.entrySet().iterator();\n            while (iterator.hasNext()) {\n                Map.Entry<JobId, JobConfig> entry = iterator.next();\n                JobId job = entry.getKey();\n                JobConfig config = entry.getValue();\n                if (job.vuid == vuid && job.clientJobId == jobId) {\n                    changed = true;\n                    mScheduler.cancel(config.virtualJobId);\n                    iterator.remove();\n                    break;\n                }\n            }\n            if (changed) {\n                saveJobs();\n            }\n        }\n    }\n\n    @Override\n    public void cancelAll() throws RemoteException {\n        int vuid = VBinder.getCallingUid();\n        synchronized (mJobStore) {\n            boolean changed = false;\n            Iterator<Map.Entry<JobId, JobConfig>> iterator = mJobStore.entrySet().iterator();\n            while (iterator.hasNext()) {\n                Map.Entry<JobId, JobConfig> entry = iterator.next();\n                JobId job = entry.getKey();\n                if (job.vuid == vuid) {\n                    JobConfig config = entry.getValue();\n                    mScheduler.cancel(config.virtualJobId);\n                    changed = true;\n                    iterator.remove();\n                    break;\n                }\n            }\n            if (changed) {\n                saveJobs();\n            }\n        }\n    }\n\n    @Override\n    public List<JobInfo> getAllPendingJobs() throws RemoteException {\n        int vuid = VBinder.getCallingUid();\n        List<JobInfo> jobs = mScheduler.getAllPendingJobs();\n        synchronized (mJobStore) {\n            Iterator<JobInfo> iterator = jobs.listIterator();\n            while (iterator.hasNext()) {\n                JobInfo job = iterator.next();\n                if (!VASettings.STUB_JOB.equals(job.getService().getClassName())) {\n                    // Schedule by Host, invisible in VA.\n                    iterator.remove();\n                    continue;\n                }\n                Map.Entry<JobId, JobConfig> jobEntry = findJobByVirtualJobId(job.getId());\n                if (jobEntry == null) {\n                    iterator.remove();\n                    continue;\n                }\n                JobId jobId = jobEntry.getKey();\n                JobConfig config = jobEntry.getValue();\n                if (jobId.vuid != vuid) {\n                    iterator.remove();\n                    continue;\n                }\n                mirror.android.app.job.JobInfo.jobId.set(job, jobId.clientJobId);\n                mirror.android.app.job.JobInfo.service.set(job, new ComponentName(jobId.packageName, config.serviceName));\n            }\n        }\n        return jobs;\n    }\n\n    @Override\n    public int enqueue(JobInfo job, JobWorkItem work) throws RemoteException {\n        return 0;\n    }\n\n    @Override\n    public JobInfo getPendingJob(int i) throws RemoteException {\n        return null;\n    }\n\n\n    public Map.Entry<JobId, JobConfig> findJobByVirtualJobId(int virtualJobId) {\n        synchronized (mJobStore) {\n            for (Map.Entry<JobId, JobConfig> entry : mJobStore.entrySet()) {\n                if (entry.getValue().virtualJobId == virtualJobId) {\n                    return entry;\n                }\n            }\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/location/VirtualLocationService.java",
    "content": "package com.lody.virtual.server.location;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.helper.PersistenceLayer;\nimport com.lody.virtual.helper.collection.SparseArray;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.remote.vloc.VCell;\nimport com.lody.virtual.remote.vloc.VLocation;\nimport com.lody.virtual.server.IVirtualLocationManager;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class VirtualLocationService extends IVirtualLocationManager.Stub {\n\n    private static final VirtualLocationService sInstance = new VirtualLocationService();\n    private final SparseArray<Map<String, VLocConfig>> mLocConfigs = new SparseArray<>();\n    private final VLocConfig mGlobalConfig = new VLocConfig();\n\n    private static final int MODE_CLOSE = 0;\n    private static final int MODE_USE_GLOBAL = 1;\n    private static final int MODE_USE_SELF = 2;\n\n    private static class VLocConfig implements Parcelable {\n        int mode;\n        VCell cell;\n        List<VCell> allCell;\n        List<VCell> neighboringCell;\n        VLocation location;\n\n        public void set(VLocConfig other) {\n            this.mode = other.mode;\n            this.cell = other.cell;\n            this.allCell = other.allCell;\n            this.neighboringCell = other.neighboringCell;\n            this.location = other.location;\n        }\n\n        VLocConfig() {\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeInt(this.mode);\n            dest.writeParcelable(this.cell, flags);\n            dest.writeTypedList(this.allCell);\n            dest.writeTypedList(this.neighboringCell);\n            dest.writeParcelable(this.location, flags);\n        }\n\n        VLocConfig(Parcel in) {\n            this.mode = in.readInt();\n            this.cell = in.readParcelable(VCell.class.getClassLoader());\n            this.allCell = in.createTypedArrayList(VCell.CREATOR);\n            this.neighboringCell = in.createTypedArrayList(VCell.CREATOR);\n            this.location = in.readParcelable(VLocation.class.getClassLoader());\n        }\n\n        public static final Creator<VLocConfig> CREATOR = new Creator<VLocConfig>() {\n            @Override\n            public VLocConfig createFromParcel(Parcel source) {\n                return new VLocConfig(source);\n            }\n\n            @Override\n            public VLocConfig[] newArray(int size) {\n                return new VLocConfig[size];\n            }\n        };\n    }\n\n    private final PersistenceLayer mPersistenceLayer = new PersistenceLayer(VEnvironment.getVirtualLocationFile()) {\n        @Override\n        public int getCurrentVersion() {\n            return 1;\n        }\n\n        @Override\n        public void writePersistenceData(Parcel p) {\n            mGlobalConfig.writeToParcel(p, 0);\n            p.writeInt(mLocConfigs.size());\n            for (int i = 0; i < mLocConfigs.size(); i++) {\n                int userId = mLocConfigs.keyAt(i);\n                Map<String, VLocConfig> pkgs = mLocConfigs.valueAt(i);\n                p.writeInt(userId);\n                p.writeMap(pkgs);\n            }\n        }\n\n        @Override\n        public void readPersistenceData(Parcel p) {\n            mGlobalConfig.set(new VLocConfig(p));\n            mLocConfigs.clear();\n            int size = p.readInt();\n            while (size-- > 0) {\n                int userId = p.readInt();\n                //noinspection unchecked\n                Map<String, VLocConfig> pkgs = p.readHashMap(getClass().getClassLoader());\n                mLocConfigs.put(userId, pkgs);\n            }\n        }\n    };\n\n    public static VirtualLocationService get() {\n        return sInstance;\n    }\n\n    private VirtualLocationService() {\n        mPersistenceLayer.read();\n    }\n\n    @Override\n    public int getMode(int userId, String pkg) throws RemoteException {\n        synchronized (mLocConfigs) {\n            VLocConfig config = getOrCreateConfig(userId, pkg);\n            mPersistenceLayer.save();\n            return config.mode;\n        }\n    }\n\n    @Override\n    public void setMode(int userId, String pkg, int mode) throws RemoteException {\n        synchronized (mLocConfigs) {\n            getOrCreateConfig(userId, pkg).mode = mode;\n            mPersistenceLayer.save();\n        }\n    }\n\n    private VLocConfig getOrCreateConfig(int userId, String pkg) {\n        Map<String, VLocConfig> pkgs = mLocConfigs.get(userId);\n        if (pkgs == null) {\n            pkgs = new HashMap<>();\n            mLocConfigs.put(userId, pkgs);\n        }\n        VLocConfig config = pkgs.get(pkg);\n        if (config == null) {\n            config = new VLocConfig();\n            config.mode = MODE_CLOSE;\n            pkgs.put(pkg, config);\n        }\n        return config;\n    }\n\n    @Override\n    public void setCell(int userId, String pkg, VCell cell) throws RemoteException {\n        getOrCreateConfig(userId, pkg).cell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public void setAllCell(int userId, String pkg, List<VCell> cell) throws RemoteException {\n        getOrCreateConfig(userId, pkg).allCell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public void setNeighboringCell(int userId, String pkg, List<VCell> cell) throws RemoteException {\n        getOrCreateConfig(userId, pkg).neighboringCell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public void setGlobalCell(VCell cell) throws RemoteException {\n        mGlobalConfig.cell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public void setGlobalAllCell(List<VCell> cell) throws RemoteException {\n        mGlobalConfig.allCell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public void setGlobalNeighboringCell(List<VCell> cell) throws RemoteException {\n        mGlobalConfig.neighboringCell = cell;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public VCell getCell(int userId, String pkg) throws RemoteException {\n        VLocConfig config = getOrCreateConfig(userId, pkg);\n        mPersistenceLayer.save();\n        switch (config.mode) {\n            case MODE_USE_SELF:\n                return config.cell;\n            case MODE_USE_GLOBAL:\n                return mGlobalConfig.cell;\n            case MODE_CLOSE:\n            default:\n                return null;\n        }\n    }\n\n    @Override\n    public List<VCell> getAllCell(int userId, String pkg) throws RemoteException {\n        VLocConfig config = getOrCreateConfig(userId, pkg);\n        mPersistenceLayer.save();\n        switch (config.mode) {\n            case MODE_USE_SELF:\n                return config.allCell;\n            case MODE_USE_GLOBAL:\n                return mGlobalConfig.allCell;\n            case MODE_CLOSE:\n            default:\n                return null;\n        }\n    }\n\n    @Override\n    public List<VCell> getNeighboringCell(int userId, String pkg) throws RemoteException {\n        VLocConfig config = getOrCreateConfig(userId, pkg);\n        mPersistenceLayer.save();\n        switch (config.mode) {\n            case MODE_USE_SELF:\n                return config.neighboringCell;\n            case MODE_USE_GLOBAL:\n                return mGlobalConfig.neighboringCell;\n            case MODE_CLOSE:\n            default:\n                return null;\n        }\n    }\n\n    @Override\n    public void setLocation(int userId, String pkg, VLocation loc) throws RemoteException {\n        getOrCreateConfig(userId, pkg).location = loc;\n        mPersistenceLayer.save();\n    }\n\n    @Override\n    public VLocation getLocation(int userId, String pkg) throws RemoteException {\n        VLocConfig config = getOrCreateConfig(userId, pkg);\n        mPersistenceLayer.save();\n        switch (config.mode) {\n            case MODE_USE_SELF:\n                return config.location;\n            case MODE_USE_GLOBAL:\n                return mGlobalConfig.location;\n            case MODE_CLOSE:\n            default:\n                return null;\n        }\n    }\n\n    @Override\n    public void setGlobalLocation(VLocation loc) throws RemoteException {\n        mGlobalConfig.location = loc;\n    }\n\n    @Override\n    public VLocation getGlobalLocation() throws RemoteException {\n        return mGlobalConfig.location;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationCompat.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport android.app.Notification;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.widget.RemoteViews;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport mirror.com.android.internal.R_Hide;\n\n/**\n * @author 247321453\n */\npublic abstract class NotificationCompat {\n\n    public static final String EXTRA_TITLE = \"android.title\";\n    public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + \".big\";\n    public static final String EXTRA_TEXT = \"android.text\";\n    public static final String EXTRA_SUB_TEXT = \"android.subText\";\n    public static final String EXTRA_INFO_TEXT = \"android.infoText\";\n    public static final String EXTRA_SUMMARY_TEXT = \"android.summaryText\";\n    public static final String EXTRA_BIG_TEXT = \"android.bigText\";\n    public static final String EXTRA_PROGRESS = \"android.progress\";\n    public static final String EXTRA_PROGRESS_MAX = \"android.progressMax\";\n    public static final String EXTRA_BUILDER_APPLICATION_INFO = \"android.appInfo\";\n    static final String TAG = NotificationCompat.class.getSimpleName();\n    static final String SYSTEM_UI_PKG = \"com.android.systemui\";\n    private final List<Integer> sSystemLayoutResIds = new ArrayList<>(10);\n    private NotificationFixer mNotificationFixer;\n\n    NotificationCompat() {\n        loadSystemLayoutRes();\n        mNotificationFixer = new NotificationFixer(this);\n    }\n\n    public static NotificationCompat create() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            return new NotificationCompatCompatV21();\n        } else {\n            return new NotificationCompatCompatV14();\n        }\n    }\n\n    private void loadSystemLayoutRes() {\n        Field[] fields = R_Hide.layout.TYPE.getFields();\n        for (Field field : fields) {\n            if (Modifier.isStatic(field.getModifiers())\n                    && Modifier.isFinal(field.getModifiers())) {\n                try {\n                    int id = field.getInt(null);\n                    sSystemLayoutResIds.add(id);\n                } catch (Throwable e) {\n                    // ignore\n                }\n            }\n        }\n    }\n\n    NotificationFixer getNotificationFixer() {\n        return mNotificationFixer;\n    }\n\n    boolean isSystemLayout(RemoteViews remoteViews) {\n        return remoteViews != null\n                && sSystemLayoutResIds.contains(remoteViews.getLayoutId());\n    }\n\n    public Context getHostContext() {\n        return VirtualCore.get().getContext();\n    }\n\n    PackageInfo getPackageInfo(String packageName) {\n        try {\n            return VirtualCore.get().getUnHookPackageManager().getPackageInfo(packageName, 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            // ignore\n        }\n        return null;\n    }\n\n    public abstract boolean dealNotification(int id, Notification notification, String packageName);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationCompatCompatV14.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport android.app.Notification;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport com.lody.virtual.client.core.VirtualCore;\n\n/**\n * @author 247321543\n */\n@SuppressWarnings(\"deprecation\")\nclass NotificationCompatCompatV14 extends NotificationCompat {\n    private final RemoteViewsFixer mRemoteViewsFixer;\n\n    NotificationCompatCompatV14() {\n        super();\n        mRemoteViewsFixer = new RemoteViewsFixer(this);\n    }\n\n    private RemoteViewsFixer getRemoteViewsFixer() {\n        return mRemoteViewsFixer;\n    }\n\n    @Override\n    public boolean dealNotification(int id, Notification notification, final String packageName) {\n        Context appContext = getAppContext(packageName);\n        if (appContext == null) {\n            return false;\n        }\n        if (VirtualCore.get().isOutsideInstalled(packageName)) {\n            if(notification.icon != 0) {\n                getNotificationFixer().fixIconImage(appContext.getResources(), notification.contentView, false, notification);\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                    getNotificationFixer().fixIconImage(appContext.getResources(), notification.bigContentView, false, notification);\n                }\n                notification.icon = getHostContext().getApplicationInfo().icon;\n            }\n            return true;\n        }\n        if (notification.tickerView != null) {\n\n            if (isSystemLayout(notification.tickerView)) {\n                getNotificationFixer().fixRemoteViewActions(appContext, false, notification.tickerView);\n            } else {\n                notification.tickerView = getRemoteViewsFixer().makeRemoteViews(id + \":tickerView\", appContext,\n                        notification.tickerView, false, false);\n            }\n        }\n        if (notification.contentView != null) {\n            if (isSystemLayout(notification.contentView)) {\n                boolean hasIconBitmap = getNotificationFixer().fixRemoteViewActions(appContext, false, notification.contentView);\n                getNotificationFixer().fixIconImage(appContext.getResources(), notification.contentView, hasIconBitmap, notification);\n            } else {\n                notification.contentView = getRemoteViewsFixer().makeRemoteViews(id + \":contentView\", appContext,\n                        notification.contentView, false, true);\n            }\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            if (notification.bigContentView != null) {\n                if (isSystemLayout(notification.bigContentView)) {\n                    getNotificationFixer().fixRemoteViewActions(appContext, false, notification.bigContentView);\n                } else {\n                    notification.bigContentView = getRemoteViewsFixer().makeRemoteViews(id + \":bigContentView\", appContext,\n                            notification.bigContentView, true, true);\n                }\n            }\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            if (notification.headsUpContentView != null) {\n                if (isSystemLayout(notification.headsUpContentView)) {\n                    boolean hasIconBitmap = getNotificationFixer().fixRemoteViewActions(appContext, false, notification.headsUpContentView);\n                    getNotificationFixer().fixIconImage(appContext.getResources(), notification.contentView, hasIconBitmap, notification);\n                } else {\n                    notification.headsUpContentView = getRemoteViewsFixer().makeRemoteViews(id + \":headsUpContentView\", appContext,\n                            notification.headsUpContentView, false, false);\n                }\n            }\n        }\n        if(notification.icon != 0) {\n            notification.icon = getHostContext().getApplicationInfo().icon;\n        }\n        return true;\n    }\n\n    Context getAppContext(final String packageName) {\n        Context context = null;\n        try {\n            context = getHostContext().createPackageContext(packageName,\n                    Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);\n        } catch (PackageManager.NameNotFoundException e) {\n           e.printStackTrace();\n        }\n        return context;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationCompatCompatV21.java",
    "content": "package com.lody.virtual.server.notification;\r\n\r\nimport android.annotation.TargetApi;\r\nimport android.app.Notification;\r\nimport android.content.Context;\r\nimport android.content.pm.ApplicationInfo;\r\nimport android.content.pm.PackageInfo;\r\nimport android.os.Build;\r\nimport android.os.Bundle;\r\nimport android.text.TextUtils;\r\nimport android.widget.RemoteViews;\r\n\r\nimport com.lody.virtual.helper.compat.SystemPropertiesCompat;\r\nimport com.lody.virtual.helper.utils.Reflect;\r\n\r\nimport static com.lody.virtual.os.VEnvironment.getPackageResourcePath;\r\n\r\n/**\r\n * @author 247321543\r\n */\r\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\r\n/* package */ class NotificationCompatCompatV21 extends NotificationCompatCompatV14 {\r\n\r\n    private static final String TAG = NotificationCompatCompatV21.class.getSimpleName();\r\n\r\n    NotificationCompatCompatV21() {\r\n        super();\r\n    }\r\n\r\n    @Override\r\n    public boolean dealNotification(int id, Notification notification, String packageName) {\r\n        Context appContext = getAppContext(packageName);\r\n        return resolveRemoteViews(appContext, packageName, notification)\r\n                || resolveRemoteViews(appContext, packageName, notification.publicVersion);\r\n    }\r\n\r\n    private boolean resolveRemoteViews(Context appContext, String packageName, Notification notification) {\r\n        if (notification == null) {\r\n            return false;\r\n        }\r\n        String sourcePath = null;\r\n        PackageInfo packageInfo = getPackageInfo(packageName);\r\n        ApplicationInfo host = getHostContext().getApplicationInfo();\r\n        if (packageInfo != null) {\r\n            sourcePath = packageInfo.applicationInfo.sourceDir;\r\n        }\r\n        if (TextUtils.isEmpty(sourcePath)) {\r\n            sourcePath = getPackageResourcePath(packageName).getAbsolutePath();\r\n        }\r\n\r\n        //Fix RemoteViews\r\n        getNotificationFixer().fixNotificationRemoteViews(appContext, notification);\r\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\r\n            getNotificationFixer().fixIcon(notification.getSmallIcon(), appContext, packageInfo != null);\r\n            getNotificationFixer().fixIcon(notification.getLargeIcon(), appContext, packageInfo != null);\r\n        } else {\r\n            getNotificationFixer().fixIconImage(appContext.getResources(), notification.contentView, false, notification);\r\n        }\r\n        notification.icon = host.icon;\r\n\r\n        ApplicationInfo proxyApplicationInfo = new ApplicationInfo(host);\r\n\r\n        proxyApplicationInfo.packageName = packageName;\r\n        proxyApplicationInfo.publicSourceDir = sourcePath;\r\n        proxyApplicationInfo.sourceDir = sourcePath;\r\n\r\n        fixApplicationInfo(notification.tickerView, proxyApplicationInfo);\r\n        fixApplicationInfo(notification.contentView, proxyApplicationInfo);\r\n        fixApplicationInfo(notification.bigContentView, proxyApplicationInfo);\r\n        fixApplicationInfo(notification.headsUpContentView, proxyApplicationInfo);\r\n        fixCustomNotificationOnColorOs(notification);\r\n        Bundle bundle = Reflect.on(notification).get(\"extras\");\r\n        if (bundle != null) {\r\n            bundle.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, proxyApplicationInfo);\r\n        }\r\n        return true;\r\n    }\r\n\r\n    private ApplicationInfo getApplicationInfo(Notification notification) {\r\n        ApplicationInfo ai = getApplicationInfo(notification.tickerView);\r\n        if (ai != null) {\r\n            return ai;\r\n        }\r\n        ai = getApplicationInfo(notification.contentView);\r\n        if (ai != null) {\r\n            return ai;\r\n        }\r\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\r\n            ai = getApplicationInfo(notification.bigContentView);\r\n            if (ai != null) {\r\n                return ai;\r\n            }\r\n        }\r\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\r\n            ai = getApplicationInfo(notification.headsUpContentView);\r\n            if (ai != null) {\r\n                return ai;\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private ApplicationInfo getApplicationInfo(RemoteViews remoteViews) {\r\n        if (remoteViews != null) {\r\n            return mirror.android.widget.RemoteViews.mApplication.get(remoteViews);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private void fixApplicationInfo(RemoteViews remoteViews, ApplicationInfo ai) {\r\n        if (remoteViews != null) {\r\n            mirror.android.widget.RemoteViews.mApplication.set(remoteViews, ai);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * http://bbs.coloros.com/thread-379265-1-1.html\r\n     * https://www.coloros.com/thread-519347-1-1.html\r\n     * @param notification the notification\r\n     */\r\n    private void fixCustomNotificationOnColorOs(Notification notification) {\r\n        final String opporom = \"ro.build.version.opporom\";\r\n        final String colorOsVersion = SystemPropertiesCompat.get(opporom, \"\");\r\n        if (TextUtils.isEmpty(colorOsVersion)) {\r\n            return;\r\n        }\r\n\r\n        // http://bbs.coloros.com/thread-311896-1-1.html\r\n        // this can take effect also, but we do not use it.\r\n        // notification.flags |= Notification.FLAG_ONGOING_EVENT;\r\n\r\n        if (!colorOsVersion.toLowerCase().startsWith(\"v3\")) {\r\n            return;\r\n        }\r\n        if (notification.contentView != null) {\r\n            notification.contentView = null;\r\n        }\r\n        if (notification.headsUpContentView != null) {\r\n            notification.headsUpContentView = null;\r\n        }\r\n        if (notification.bigContentView != null) {\r\n            notification.bigContentView = null;\r\n        }\r\n        if (notification.tickerView != null) {\r\n            notification.tickerView = null;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/NotificationFixer.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport android.annotation.TargetApi;\nimport android.app.Notification;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.Icon;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.widget.RemoteViews;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.utils.OSUtils;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport mirror.com.android.internal.R_Hide;\n\n/* package */ class NotificationFixer {\n\n    private static final String TAG = NotificationCompat.TAG;\n    private NotificationCompat mNotificationCompat;\n\n    NotificationFixer(NotificationCompat notificationCompat) {\n        this.mNotificationCompat = notificationCompat;\n    }\n\n    private static void fixNotificationIcon(Context context, Notification notification, Notification.Builder builder) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            //noinspection deprecation\n            builder.setSmallIcon(notification.icon);\n            //noinspection deprecation\n            builder.setLargeIcon(notification.largeIcon);\n        } else {\n            Icon icon = notification.getSmallIcon();\n            if (icon != null) {\n                Bitmap bitmap = drawableToBitMap(icon.loadDrawable(context));\n                if (bitmap != null) {\n                    Icon newIcon = Icon.createWithBitmap(bitmap);\n                    builder.setSmallIcon(newIcon);\n                }\n            }\n            Icon largeIcon = notification.getLargeIcon();\n            if (largeIcon != null) {\n                Bitmap bitmap = drawableToBitMap(largeIcon.loadDrawable(context));\n                if (bitmap != null) {\n                    Icon newIcon = Icon.createWithBitmap(bitmap);\n                    builder.setLargeIcon(newIcon);\n                }\n            }\n        }\n    }\n\n    private static Bitmap drawableToBitMap(Drawable drawable) {\n        if (drawable == null) {\n            return null;\n        }\n        if (drawable instanceof BitmapDrawable) {\n            BitmapDrawable bitmapDrawable = ((BitmapDrawable) drawable);\n            return bitmapDrawable.getBitmap();\n        } else {\n            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),\n                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);\n            Canvas canvas = new Canvas(bitmap);\n            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());\n            drawable.draw(canvas);\n            return bitmap;\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    void fixIcon(Icon icon, Context appContext, boolean installed) {\n        if (icon == null) {\n            return;\n        }\n        int type = mirror.android.graphics.drawable.Icon.mType.get(icon);\n        if (type == mirror.android.graphics.drawable.Icon.TYPE_RESOURCE) {\n            if (installed) {\n                mirror.android.graphics.drawable.Icon.mObj1.set(icon, appContext.getResources());\n                mirror.android.graphics.drawable.Icon.mString1.set(icon, appContext.getPackageName());\n            } else {\n                Drawable drawable = icon.loadDrawable(appContext);\n                Bitmap bitmap = drawableToBitMap(drawable);\n                mirror.android.graphics.drawable.Icon.mObj1.set(icon, bitmap);\n                mirror.android.graphics.drawable.Icon.mString1.set(icon, null);\n                mirror.android.graphics.drawable.Icon.mType.set(icon, mirror.android.graphics.drawable.Icon.TYPE_BITMAP);\n            }\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    void fixNotificationRemoteViews(Context pluginContext, Notification notification) {\n        Notification.Builder rebuild = null;\n        try {\n            rebuild = Reflect.on(Notification.Builder.class).create(pluginContext, notification).get();\n        } catch (Exception e) {\n            // ignore\n        }\n        if (rebuild != null) {\n            Notification renotification = rebuild.build();\n            if (notification.tickerView == null) {\n                notification.tickerView = renotification.tickerView;\n            }\n            if (notification.contentView == null) {\n                notification.contentView = renotification.contentView;\n            }\n            if (notification.bigContentView == null) {\n                notification.bigContentView = renotification.bigContentView;\n            }\n            if (notification.headsUpContentView == null) {\n                notification.headsUpContentView = renotification.headsUpContentView;\n            }\n        }\n    }\n\n    boolean fixRemoteViewActions(Context appContext, boolean installed, final RemoteViews remoteViews) {\n        boolean hasIcon = false;\n        if (remoteViews != null) {\n            int systemIconViewId = R_Hide.id.icon.get();\n            List<BitmapReflectionAction> mNew = new ArrayList<>();\n            ArrayList<Object> mActions = Reflect.on(remoteViews).get(\"mActions\");\n            if (mActions != null) {\n                int count = mActions.size();\n                for (int i = count - 1; i >= 0; i--) {\n                    Object action = mActions.get(i);\n                    if (action == null) {\n                        continue;\n                    }\n                    //TextViewDrawableAction\n                    //setImageURI\n                    //setLabelFor\n                    if (action.getClass().getSimpleName().endsWith(\"TextViewDrawableAction\")) {\n                        mActions.remove(action);\n                        continue;\n                    }\n                    if (ReflectionActionCompat.isInstance(action)\n                            || (action.getClass().getSimpleName().endsWith(\"ReflectionAction\"))) {\n                        int viewId = Reflect.on(action).get(\"viewId\");\n\n                        String methodName = Reflect.on(action).get(\"methodName\");\n                        int type = Reflect.on(action).get(\"type\");\n                        Object value = Reflect.on(action).get(\"value\");\n                        if (!hasIcon) {\n                            hasIcon = viewId == systemIconViewId;\n                            if (hasIcon) {\n                                if (type == ReflectionActionCompat.INT && (int) value == 0) {\n                                    hasIcon = false;\n                                }\n                                if (hasIcon) {\n                                    VLog.v(TAG, \"find icon \" + methodName + \" type=\" + type + \", value=\" + value);\n                                }\n                            }\n                        }\n                        if (methodName.equals(\"setImageResource\")) {\n                            //setImageBitmap\n                            mNew.add(new BitmapReflectionAction(viewId, \"setImageBitmap\",\n                                    drawableToBitMap(appContext.getResources().getDrawable((int) value))));\n                            mActions.remove(action);\n                        } else if (methodName.equals(\"setText\") && type == ReflectionActionCompat.INT) {\n                            //setText string\n                            Reflect.on(action).set(\"type\", ReflectionActionCompat.STRING);\n                            Reflect.on(action).set(\"value\", appContext.getResources().getString((int) value));\n                        } else if (methodName.equals(\"setLabelFor\")) {\n                            //TODO remove\n                            mActions.remove(action);\n                        } else if (methodName.equals(\"setBackgroundResource\")) {\n                            //TODO remove\n                            mActions.remove(action);\n                        } else if (methodName.equals(\"setImageURI\")) {\n                            Uri uri = (Uri) value;\n                            if (!uri.getScheme().startsWith(\"http\")) {\n                                mActions.remove(action);\n                            }\n                        } else {\n                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                                if (value instanceof Icon) {\n                                    Icon icon = (Icon) value;\n                                    fixIcon(icon, appContext, installed);\n                                }\n                            }\n                        }\n                    }\n                }\n                for (BitmapReflectionAction action : mNew) {\n                    remoteViews.setBitmap(action.viewId, action.methodName, action.bitmap);\n                }\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {\n                mirror.android.widget.RemoteViews.mPackage.set(remoteViews, VirtualCore.get().getHostPkg());\n            }\n        }\n        return hasIcon;\n    }\n\n    void fixIconImage(Resources resources, RemoteViews remoteViews, boolean hasIconBitmap, Notification notification) {\n        if (remoteViews == null || notification.icon == 0) return;\n        if (!mNotificationCompat.isSystemLayout(remoteViews)) {\n            return;\n        }\n        try {\n            //noinspection deprecation\n            int id = R_Hide.id.icon.get();\n            //only fake small icon\n            if (!hasIconBitmap && notification.largeIcon == null) {\n                Drawable drawable = resources.getDrawable(notification.icon);\n                drawable.setLevel(notification.iconLevel);\n                Bitmap bitmap = drawableToBitMap(drawable);\n                remoteViews.setImageViewBitmap(id, bitmap);\n                //emui\n                if(OSUtils.getInstance().isEmui()) {\n                    if (notification.largeIcon == null) {\n                        notification.largeIcon = bitmap;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private static class BitmapReflectionAction {\n        int viewId;\n        String methodName;\n        Bitmap bitmap;\n\n        BitmapReflectionAction(int viewId, String methodName, Bitmap bitmap) {\n            this.viewId = viewId;\n            this.methodName = methodName;\n            this.bitmap = bitmap;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/PendIntentCompat.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport android.app.PendingIntent;\nimport android.graphics.Rect;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewParent;\nimport android.widget.ImageView;\nimport android.widget.RemoteViews;\nimport android.widget.TextView;\n\nimport static com.lody.virtual.server.notification.NotificationCompat.TAG;\n\n/***\n * Remoteviews's PendIntent\n *\n * @author 247321453\n */\nclass PendIntentCompat {\n    private RemoteViews mRemoteViews;\n    private Map<Integer, PendingIntent> clickIntents;\n\n    PendIntentCompat(RemoteViews mRemoteViews) {\n        this.mRemoteViews = mRemoteViews;\n    }\n\n    public int findPendIntents() {\n        if (clickIntents == null) {\n            clickIntents = getClickIntents(mRemoteViews);\n        }\n        return clickIntents.size();\n    }\n\n    /**\n     *\n     * @param remoteViews notification's old remoteViews\n     * @param remoteview notification's old remoteViews view\n     * @param oldRemoteView notification's new remoteViews view\n     */\n    public void setPendIntent(RemoteViews remoteViews, View remoteview, View oldRemoteView) {\n        if (findPendIntents() > 0) {\n            Iterator<Map.Entry<Integer, PendingIntent>> set = clickIntents.entrySet().iterator();\n            List<RectInfo> list = new ArrayList<>();\n            int index = 0;\n            VLog.v(TAG, \"start find intent\");\n            while (set.hasNext()) {\n                Map.Entry<Integer, PendingIntent> e = set.next();\n                View view = oldRemoteView.findViewById(e.getKey());\n                if (view != null) {\n                    Rect rect = getRect(view);\n                    list.add(new RectInfo(rect, e.getValue(), index));\n                    index++;\n                }\n            }\n            VLog.v(TAG, \"find:\" + list);\n            if (remoteview instanceof ViewGroup) {\n                setIntentByViewGroup(remoteViews, (ViewGroup) remoteview, list);\n            }\n        }\n    }\n\n    private Rect getRect(View view) {\n        Rect rect = new Rect();\n        rect.top = view.getTop();\n        rect.left = view.getLeft();\n        rect.right = view.getRight();\n        rect.bottom = view.getBottom();\n\n        ViewParent viewParent = view.getParent();\n        if (viewParent != null) {\n            if (viewParent instanceof ViewGroup) {\n                Rect prect = getRect((ViewGroup) viewParent);\n                rect.top += prect.top;\n                rect.left += prect.left;\n                rect.right += prect.left;\n                rect.bottom += prect.top;\n            }\n        }\n        return rect;\n    }\n\n    private void setIntentByViewGroup(RemoteViews remoteViews, ViewGroup viewGroup, List<RectInfo> list) {\n        int count = viewGroup.getChildCount();\n        Rect p = new Rect();\n        viewGroup.getHitRect(p);\n        for (int i = 0; i < count; i++) {\n            View v = viewGroup.getChildAt(i);\n            if (v instanceof ViewGroup) {\n                // linearlayout\n                setIntentByViewGroup(remoteViews, (ViewGroup) v, list);\n            } else if (v instanceof TextView || v instanceof ImageView) {\n                // textview\n                Rect rect = getRect(v);\n                RectInfo next = findIntent(rect, list);\n                if (next != null) {\n//\t\t\t\t\tVLog.d(TAG, next.rect+\":setPendIntent:\"+i);\n//                    remoteViews.setImageViewBitmap(v.getId(), next.testBg);\n                    remoteViews.setOnClickPendingIntent(v.getId(), next.mPendingIntent);\n                }\n            }\n        }\n    }\n\n    private RectInfo findIntent(Rect rect, List<RectInfo> list) {\n        int maxArea = 0;\n        RectInfo next = null;\n        for (RectInfo rectInfo : list) {\n            int size = getOverlapArea(rect, rectInfo.rect);\n            if (size > maxArea) {\n                if (size == 0) {\n                    Log.w(\"PendingIntentCompat\", \"find two:\" + rectInfo.rect);\n                }\n                maxArea = size;\n                next = rectInfo;\n            }\n        }\n        return next;\n    }\n\n    private int getOverlapArea(Rect rect1, Rect rect2) {\n        Rect rect = new Rect();\n        rect.left = Math.max(rect1.left, rect2.left);\n        rect.top = Math.max(rect1.top, rect2.top);\n        rect.right = Math.min(rect1.right, rect2.right);\n        rect.bottom = Math.min(rect1.bottom, rect2.bottom);\n        if (rect.left < rect.right && rect.top < rect.bottom) {\n            return (rect.right - rect.left) * (rect.bottom - rect.top);\n        }\n        return 0;\n    }\n\n    private Map<Integer, PendingIntent> getClickIntents(RemoteViews remoteViews) {\n        Map<Integer, PendingIntent> map = new HashMap<>();\n        if (remoteViews == null)\n            return map;\n        Object mActionsObj = null;\n        try {\n            mActionsObj = Reflect.on(remoteViews).get(\"mActions\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        if (mActionsObj == null) {\n            return map;\n        }\n        if (mActionsObj instanceof Collection) {\n            Collection mActions = (Collection) mActionsObj;\n            for (Object one : mActions) {\n                if (one != null) {\n                    String action;\n                    try {\n                        action = Reflect.on(one).call(\"getActionName\").get();\n                    } catch (Exception e) {\n                        action = one.getClass().getSimpleName();\n                    }\n                    if (\"SetOnClickPendingIntent\".equalsIgnoreCase(action)) {\n                        int id = Reflect.on(one).get(\"viewId\");\n                        PendingIntent intent = Reflect.on(one).get(\"pendingIntent\");\n                        map.put(id, intent);\n                    }\n                }\n            }\n        }\n        return map;\n    }\n\n    class RectInfo {\n        Rect rect;\n        PendingIntent mPendingIntent;\n        int index;\n\n        public RectInfo(Rect rect, PendingIntent pendingIntent, int index) {\n            this.rect = rect;\n            mPendingIntent = pendingIntent;\n            this.index = index;\n        }\n\n        @Override\n        public String toString() {\n            return \"RectInfo{\" +\n                    \"rect=\" + rect +\n                    '}';\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/ReflectionActionCompat.java",
    "content": "package com.lody.virtual.server.notification;\r\n\r\nimport android.widget.RemoteViews;\r\n\r\n\r\n/* package */ class ReflectionActionCompat {\r\n    private static Class ReflectionActionClass;\r\n    private static final String ReflectionAction = \"ReflectionAction\";\r\n\r\n    static final int TAG = 2;\r\n\r\n    static final int BOOLEAN = 1;\r\n    static final int BYTE = 2;\r\n    static final int SHORT = 3;\r\n    static final int INT = 4;\r\n    static final int LONG = 5;\r\n    static final int FLOAT = 6;\r\n    static final int DOUBLE = 7;\r\n    static final int CHAR = 8;\r\n    static final int STRING = 9;\r\n    static final int CHAR_SEQUENCE = 10;\r\n    static final int URI = 11;\r\n    // BITMAP actions are never stored in the list of actions. They are only used locally\r\n    // to implement BitmapReflectionAction, which eliminates duplicates using BitmapCache.\r\n    static final int BITMAP = 12;\r\n    static final int BUNDLE = 13;\r\n    static final int INTENT = 14;\r\n    static final int COLOR_STATE_LIST = 15;\r\n    static final int ICON = 16;\r\n\r\n    static {\r\n        try {\r\n            ReflectionActionClass = Class.forName(RemoteViews.class.getName() + \"$\" + ReflectionAction);\r\n        } catch (ClassNotFoundException e) {\r\n        }\r\n    }\r\n\r\n    static boolean isInstance(Object object) {\r\n        return ReflectionActionClass != null && ReflectionActionClass.isInstance(object);\r\n    }\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/RemoteViewsFixer.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.os.Build;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.EditorInfo;\nimport android.widget.FrameLayout;\nimport android.widget.RemoteViews;\nimport android.widget.TextView;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.helper.utils.Reflect;\nimport com.lody.virtual.helper.utils.VLog;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\n\n/* package */ class RemoteViewsFixer {\n    private static final String TAG = NotificationCompat.TAG;\n    private final WidthCompat mWidthCompat;\n    private int notification_min_height, notification_max_height, notification_mid_height;\n    private int notification_panel_width;\n    private int notification_side_padding;\n    private int notification_padding;\n\n    private final HashMap<String, Bitmap> mImages = new HashMap<>();\n    private NotificationCompat mNotificationCompat;\n\n    RemoteViewsFixer(NotificationCompat notificationCompat) {\n        mWidthCompat = new WidthCompat();\n        mNotificationCompat = notificationCompat;\n    }\n\n    View toView(final Context context, RemoteViews remoteViews, boolean isBig, boolean systemId) {\n        View mCache = null;\n        try {\n            mCache = createView(context, remoteViews, isBig, systemId);\n        } catch (Throwable throwable) {\n            VLog.w(TAG, \"toView 1\", throwable);\n            try {\n                mCache = LayoutInflater.from(context).inflate(remoteViews.getLayoutId(), null);\n            } catch (Throwable e) {\n                VLog.w(TAG, \"toView 2\", e);\n            }\n        }\n        return mCache;\n    }\n\n    Bitmap createBitmap(View mCache) {\n        if (mCache == null) {\n            return null;\n        }\n        mCache.setDrawingCacheEnabled(true);\n        mCache.buildDrawingCache();\n        return mCache.getDrawingCache();\n    }\n\n    private View apply(Context context, RemoteViews remoteViews) {\n        View view = null;\n        try {\n            view = LayoutInflater.from(context).inflate(remoteViews.getLayoutId(), null, false);\n            try {\n                Reflect.on(view).call(\"setTagInternal\", Reflect.on(\"com.android.internal.R$id\").get(\"widget_frame\"), remoteViews.getLayoutId());\n            } catch (Exception e2) {\n                VLog.w(TAG, \"setTagInternal\", e2);\n            }\n        } catch (Exception e) {\n            VLog.w(TAG, \"inflate\", e);\n        }\n        if (view != null) {\n            ArrayList<Object> mActions = Reflect.on(remoteViews).get(\"mActions\");\n            if (mActions != null) {\n                VLog.d(TAG, \"apply actions:\"+mActions.size());\n                for (Object action : mActions) {\n                    try {\n                        Reflect.on(action).call(\"apply\", view, null, null);\n                    } catch (Exception e) {\n                        VLog.w(TAG, \"apply action\", e);\n                    }\n                }\n            }\n        } else {\n            VLog.e(TAG, \"create views\");\n        }\n        return view;\n    }\n\n    private View createView(final Context context, RemoteViews remoteViews, boolean isBig, boolean systemId) {\n        if (remoteViews == null)\n            return null;\n        Context base = mNotificationCompat.getHostContext();\n        init(base);\n        VLog.v(TAG, \"createView:big=\" + isBig + \",system=\" + systemId);\n\n        int height = isBig ? notification_max_height : notification_min_height;\n        int width = mWidthCompat.getNotificationWidth(base, notification_panel_width, height,\n                notification_side_padding);\n        VLog.v(TAG, \"createView:getNotificationWidth=\" + width);\n        ViewGroup frameLayout = new FrameLayout(context);\n        VLog.v(TAG, \"createView:apply\");\n\n        View view1 = apply(context, remoteViews);\n\n        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,\n                ViewGroup.LayoutParams.MATCH_PARENT);\n        params.gravity = Gravity.CENTER_VERTICAL;\n        frameLayout.addView(view1, params);\n        if (view1 instanceof ViewGroup) {\n            VLog.v(TAG, \"createView:fixTextView\");\n            fixTextView((ViewGroup) view1);\n        }\n        int mode;\n        //TODO need adaptation\n        if (systemId) {\n            mode = View.MeasureSpec.EXACTLY;\n        } else {\n            if (isBig) {\n                mode = View.MeasureSpec.AT_MOST;\n            } else {\n                mode = View.MeasureSpec.EXACTLY;\n            }\n        }\n        VLog.v(TAG, \"createView:layout\");\n        View mCache = frameLayout;\n        mCache.layout(0, 0, width, height);\n        mCache.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),\n                View.MeasureSpec.makeMeasureSpec(height, mode));\n        mCache.layout(0, 0, width, mCache.getMeasuredHeight());\n        VLog.v(TAG, \"notification:systemId=\" + systemId + \",max=%d/%d, szie=%d/%d\", width, height,\n                mCache.getMeasuredWidth(), mCache.getMeasuredHeight());\n        return mCache;\n    }\n\n    private void fixTextView(ViewGroup viewGroup) {\n        int count = viewGroup.getChildCount();\n        for (int i = 0; i < count; i++) {\n            View v = viewGroup.getChildAt(i);\n            if (v instanceof TextView) {\n                TextView tv = (TextView) v;\n                if (isSingleLine(tv)) {\n                    tv.setSingleLine(false);\n                    tv.setMaxLines(1);\n                }\n            } else if (v instanceof ViewGroup) {\n                fixTextView((ViewGroup) v);\n            }\n        }\n    }\n\n    private boolean isSingleLine(TextView textView) {\n        boolean singleLine;\n        try {\n            singleLine = Reflect.on(textView).get(\"mSingleLine\");\n        } catch (Exception e) {\n            singleLine = (textView.getInputType() & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) != 0;\n        }\n        return singleLine;\n    }\n\n    public RemoteViews makeRemoteViews(String key, Context pluginContext, RemoteViews contentView, boolean isBig, boolean click) {\n        if (contentView == null) {\n            return null;\n        }\n        final boolean systemId = false;\n        final PendIntentCompat pendIntentCompat = new PendIntentCompat(contentView);\n        final int layoutId;\n        if (!click || pendIntentCompat.findPendIntents() <= 0) {\n            layoutId = R.layout.custom_notification_lite;\n        } else {\n            layoutId = R.layout.custom_notification;\n        }\n        VLog.v(TAG, \"createviews id = \" + layoutId);\n        //make a remoteViews\n        RemoteViews remoteViews = new RemoteViews(mNotificationCompat.getHostContext().getPackageName(), layoutId);\n        VLog.v(TAG, \"remoteViews to view\");\n        View cache = toView(pluginContext, contentView, isBig, systemId);\n        // remoteViews to bitmap\n        VLog.v(TAG, \"start createBitmap\");\n        final Bitmap bmp = createBitmap(cache);\n        if (bmp == null) {\n            VLog.e(TAG, \"bmp is null,contentView=\" + contentView);\n            // return null; //ignore notification\n        } else {\n            VLog.v(TAG, \"bmp w=\" + bmp.getWidth() + \",h=\" + bmp.getHeight());\n        }\n        Bitmap old;\n        synchronized (mImages) {\n            old = mImages.get(key);\n        }\n        if (old != null && !old.isRecycled()) {\n            VLog.v(TAG, \"recycle \" + key);\n            old.recycle();\n        }\n        remoteViews.setImageViewBitmap(R.id.im_main, bmp);\n        VLog.v(TAG, \"createview \" + key);\n        synchronized (mImages) {\n            mImages.put(key, bmp);\n        }\n        //notification's click\n        if (click) {\n            if (layoutId == R.layout.custom_notification) {\n                VLog.v(TAG, \"start setPendIntent\");\n                try {\n                    pendIntentCompat.setPendIntent(remoteViews,\n                            toView(mNotificationCompat.getHostContext(), remoteViews, isBig, systemId),\n                            cache);\n                } catch (Exception e) {\n                    VLog.e(TAG, \"setPendIntent error\", e);\n                }\n            }\n        }\n        return remoteViews;\n    }\n\n    private boolean init = false;\n\n    private void init(Context context) {\n        if (init) return;\n        init = true;\n        if (notification_panel_width == 0) {\n            Context systemUi = null;\n            try {\n                systemUi = context.createPackageContext(NotificationCompat.SYSTEM_UI_PKG, Context.CONTEXT_IGNORE_SECURITY);\n            } catch (PackageManager.NameNotFoundException e) {\n            }\n            if (Build.VERSION.SDK_INT <= 19) {\n                notification_side_padding = 0;\n            } else {\n                notification_side_padding = getDimem(context, systemUi, \"notification_side_padding\",\n                        R.dimen.notification_side_padding);\n            }\n            notification_panel_width = getDimem(context, systemUi, \"notification_panel_width\",\n                    R.dimen.notification_panel_width);\n            if (notification_panel_width <= 0) {\n                notification_panel_width = context.getResources().getDisplayMetrics().widthPixels;\n            }\n            notification_min_height = getDimem(context, systemUi, \"notification_min_height\",\n                    R.dimen.notification_min_height);\n            // getDimem(context, systemUi, \"notification_row_min_height\", 0);\n            // if (notification_min_height == 0) {\n            // notification_min_height =\n            // }\n            notification_max_height = getDimem(context, systemUi, \"notification_max_height\",\n                    R.dimen.notification_max_height);\n            notification_mid_height = getDimem(context, systemUi, \"notification_mid_height\",\n                    R.dimen.notification_mid_height);\n            notification_padding = getDimem(context, systemUi, \"notification_padding\", R.dimen.notification_padding);\n            // notification_collapse_second_card_padding\n        }\n    }\n\n    private int getDimem(Context context, Context sysContext, String name, int defId) {\n        if (sysContext != null) {\n            int id = sysContext.getResources().getIdentifier(name, \"dimen\", NotificationCompat.SYSTEM_UI_PKG);\n            if (id != 0) {\n                try {\n                    return Math.round(sysContext.getResources().getDimension(id));\n                } catch (Exception e) {\n\n                }\n            }\n        }\n        // VLog.w(TAG, \"use my dimen:\" + name);\n        return defId == 0 ? 0 : Math.round(context.getResources().getDimension(defId));\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/VNotificationManagerService.java",
    "content": "package com.lody.virtual.server.notification;\r\n\r\nimport android.app.NotificationManager;\r\nimport android.content.Context;\r\nimport android.text.TextUtils;\r\n\r\nimport com.lody.virtual.helper.utils.VLog;\r\nimport com.lody.virtual.server.INotificationManager;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.concurrent.atomic.AtomicReference;\r\n\r\npublic class VNotificationManagerService extends INotificationManager.Stub {\r\n    private static final AtomicReference<VNotificationManagerService> gService = new AtomicReference<>();\r\n    private NotificationManager mNotificationManager;\r\n    static final String TAG = NotificationCompat.class.getSimpleName();\r\n    private final List<String> mDisables = new ArrayList<>();\r\n    //VApp's Notifications\r\n    private final HashMap<String, List<NotificationInfo>> mNotifications = new HashMap<>();\r\n    private Context mContext;\r\n\r\n    private VNotificationManagerService(Context context) {\r\n        mContext = context;\r\n        mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\r\n    }\r\n\r\n    public static void systemReady(Context context) {\r\n        VNotificationManagerService instance = new VNotificationManagerService(context);\r\n        gService.set(instance);\r\n    }\r\n\r\n    public static VNotificationManagerService get() {\r\n        return gService.get();\r\n    }\r\n\r\n    /***\r\n     * fake notification's id\r\n     *\r\n     * @param id          notification's id\r\n     * @param packageName notification's package\r\n     * @param userId      user\r\n     * @return\r\n     */\r\n    @Override\r\n    public int dealNotificationId(int id, String packageName, String tag, int userId) {\r\n        return id;\r\n    }\r\n\r\n    /***\r\n     * fake notification's tag\r\n     *\r\n     * @param id          notification's id\r\n     * @param packageName notification's package\r\n     * @param tag         notification's tag\r\n     * @param userId      user\r\n     * @return\r\n     */\r\n    @Override\r\n    public String dealNotificationTag(int id, String packageName, String tag, int userId) {\r\n        if (TextUtils.equals(mContext.getPackageName(), packageName)) {\r\n            return tag;\r\n        }\r\n        if (tag == null) {\r\n            return packageName + \"@\" + userId;\r\n        }\r\n        return packageName + \":\" + tag + \"@\" + userId;\r\n    }\r\n\r\n    @Override\r\n    public boolean areNotificationsEnabledForPackage(String packageName, int userId) {\r\n        return !mDisables.contains(packageName + \":\" + userId);\r\n    }\r\n\r\n    @Override\r\n    public void setNotificationsEnabledForPackage(String packageName, boolean enable, int userId) {\r\n        String key = packageName + \":\" + userId;\r\n        if (enable) {\r\n            if (mDisables.contains(key)) {\r\n                mDisables.remove(key);\r\n            }\r\n        } else {\r\n            if (!mDisables.contains(key)) {\r\n                mDisables.add(key);\r\n            }\r\n        }\r\n        //TODO: save mDisables ?\r\n    }\r\n\r\n    @Override\r\n    public void addNotification(int id, String tag, String packageName, int userId) {\r\n        NotificationInfo notificationInfo = new NotificationInfo(id, tag, packageName, userId);\r\n        synchronized (mNotifications) {\r\n            List<NotificationInfo> list = mNotifications.get(packageName);\r\n            if (list == null) {\r\n                list = new ArrayList<>();\r\n                mNotifications.put(packageName, list);\r\n            }\r\n            if (!list.contains(notificationInfo)) {\r\n                list.add(notificationInfo);\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void cancelAllNotification(String packageName, int userId) {\r\n        List<NotificationInfo> infos = new ArrayList<>();\r\n        synchronized (mNotifications) {\r\n            List<NotificationInfo> list = mNotifications.get(packageName);\r\n            if (list != null) {\r\n                int count = list.size();\r\n                for (int i = count - 1; i >= 0; i--) {\r\n                    NotificationInfo info = list.get(i);\r\n                    if (info.userId == userId) {\r\n                        infos.add(info);\r\n                        list.remove(i);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        for (NotificationInfo info : infos) {\r\n            VLog.d(TAG, \"cancel \" + info.tag + \" \" + info.id);\r\n            mNotificationManager.cancel(info.tag, info.id);\r\n        }\r\n    }\r\n\r\n    private static class NotificationInfo {\r\n        int id;\r\n        String tag;\r\n        String packageName;\r\n        int userId;\r\n\r\n        NotificationInfo(int id, String tag, String packageName, int userId) {\r\n            this.id = id;\r\n            this.tag = tag;\r\n            this.packageName = packageName;\r\n            this.userId = userId;\r\n        }\r\n\r\n        @Override\r\n        public boolean equals(Object obj) {\r\n            if (obj instanceof NotificationInfo) {\r\n                NotificationInfo that = (NotificationInfo) obj;\r\n                return that.id == id && TextUtils.equals(that.tag, tag)\r\n                        && TextUtils.equals(packageName, that.packageName)\r\n                        && that.userId == userId;\r\n            }\r\n            return super.equals(obj);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/notification/WidthCompat.java",
    "content": "package com.lody.virtual.server.notification;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\n\nimport com.lody.virtual.helper.utils.OSUtils;\n\n/**\n * Created by 247321453 on 2016/7/17.\n * notification's width\n */\n\n/* package */ class WidthCompat {\n    private final static String TAG = WidthCompat.class.getSimpleName();\n    private volatile int mWidth = 0;\n\n    public int getNotificationWidth(Context context, int width, int height, int padding) {\n        if (mWidth > 0) {\n            return mWidth;\n        }\n        int w = getDefaultWidth(width, padding);\n        if (OSUtils.getInstance().isEmui()) {\n            // huawei's emui\n            w = getEMUINotificationWidth(context, width, height);\n        } else if (OSUtils.getInstance().isMiui()) {\n            if (Build.VERSION.SDK_INT >= 21) {\n                padding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f,\n                        context.getResources().getDisplayMetrics()));\n                w = getMIUINotificationWidth(context, width - padding * 2, height);\n            } else {\n                padding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25f,\n                        context.getResources().getDisplayMetrics()));\n                w = getMIUINotificationWidth(context, width - padding * 2, height);\n            }\n        }\n        mWidth = w;\n        return w;\n    }\n\n    private int getDefaultWidth(int width, int padding) {\n        if (Build.VERSION.SDK_INT >= 21)\n            return width - padding * 2;\n        return width;\n    }\n\n\n    private int getMIUINotificationWidth(Context context, int width, int height) {\n        // status_bar_notification_row\n        // adaptive\n        // content\n        try {\n            Context systemUi = context.createPackageContext(NotificationCompat.SYSTEM_UI_PKG,\n                    Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);\n            int layoutId = getSystemId(systemUi, \"status_bar_notification_row\", \"layout\");\n            // status_bar_notification_row\n            if (layoutId != 0) {\n                ViewGroup viewGroup = createViewGroup(systemUi, layoutId);\n\n                int lid = getSystemId(systemUi, \"adaptive\", \"id\");\n                if (lid == 0) {\n                    lid = getSystemId(systemUi, \"content\", \"id\");\n                } else {\n                    // miui5的子view不存在的空指针\n                    View child = viewGroup.findViewById(lid);\n                    if (child != null && child instanceof ViewGroup) {\n                        ((ViewGroup) child).addView(new View(systemUi));\n                    }\n                }\n                layout(viewGroup, width, height);\n                if (lid != 0) {\n                    View child = viewGroup.findViewById(lid);\n                    if (child != null) {\n                        return width - child.getLeft() - child.getPaddingLeft() - child.getPaddingRight();\n                    }\n                } else {\n                    int count = viewGroup.getChildCount();\n                    for (int i = 0; i < count; i++) {\n                        View child = viewGroup.getChildAt(i);\n                        if (FrameLayout.class.isInstance(child) || \"LatestItemView\".equals(child.getClass().getName())\n                                || \"SizeAdaptiveLayout\".equals(child.getClass().getName())) {\n                            return width - child.getLeft() - child.getPaddingLeft() - child.getPaddingRight();// (LinearLayout)child;\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            // ignore\n        }\n        return width;\n    }\n\n    /**\n     * emui 3.0\n     */\n    private int getEMUINotificationWidth(Context context, int width, int height) {\n        try {\n            Context systemUi = context.createPackageContext(NotificationCompat.SYSTEM_UI_PKG,\n                    Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);\n            int layoutId = getSystemId(systemUi, \"time_axis\", \"layout\");\n            if (layoutId != 0) {\n                ViewGroup viewGroup = createViewGroup(systemUi, layoutId);\n                layout(viewGroup, width, height);\n                int lid = getSystemId(systemUi, \"content_view_group\", \"id\");\n                if (lid != 0) {\n                    View child = viewGroup.findViewById(lid);\n                    return width - child.getLeft() - child.getPaddingLeft() - child.getPaddingRight();\n                } else {\n                    int count = viewGroup.getChildCount();\n                    for (int i = 0; i < count; i++) {\n                        View child = viewGroup.getChildAt(i);\n                        if (LinearLayout.class.isInstance(child)) {\n                            // (LinearLayout)child;\n                            return width - child.getLeft() - child.getPaddingLeft() - child.getPaddingRight();\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            // ignore\n        }\n        return width;\n    }\n\n    private int getSystemId(Context systemUi, String name, String type) {\n        return systemUi.getResources().getIdentifier(name, type, NotificationCompat.SYSTEM_UI_PKG);\n    }\n\n    private ViewGroup createViewGroup(Context context, int layoutId) {\n        try {\n            return (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);\n        } catch (Throwable e) {\n            // ignore\n        }\n        return new FrameLayout(context);\n    }\n\n    private void layout(View view, int width, int height) {\n        view.layout(0, 0, width, height);\n        view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST),\n                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST));\n        view.layout(0, 0, width, height);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/FastImmutableArraySet.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.server.pm;\n\nimport java.util.AbstractSet;\nimport java.util.Iterator;\n\n/**\n * A fast immutable set wrapper for an array that is optimized for\n * non-concurrent iteration. The same iterator instance is reused each time to\n * avoid creating lots of garbage. Iterating over an array in this fashion is\n * 2.5x faster than iterating over a {@link java.util.HashSet} so it is worth\n * copying the contents of the set to an array when iterating over it hundreds\n * of times.\n * \n * @hide\n */\npublic final class FastImmutableArraySet<T> extends AbstractSet<T> {\n\tFastIterator<T> mIterator;\n\tT[] mContents;\n\n\tpublic FastImmutableArraySet(T[] contents) {\n\t\tmContents = contents;\n\t}\n\n\t@Override\n\tpublic Iterator<T> iterator() {\n\t\tFastIterator<T> it = mIterator;\n\t\tif (it == null) {\n\t\t\tit = new FastIterator<T>(mContents);\n\t\t\tmIterator = it;\n\t\t} else {\n\t\t\tit.mIndex = 0;\n\t\t}\n\t\treturn it;\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn mContents.length;\n\t}\n\n\tprivate static final class FastIterator<T> implements Iterator<T> {\n\t\tprivate final T[] mContents;\n\t\tint mIndex;\n\n\t\tpublic FastIterator(T[] contents) {\n\t\t\tmContents = contents;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\treturn mIndex != mContents.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic T next() {\n\t\t\treturn mContents[mIndex++];\n\t\t}\n\n\t\t@Override\n\t\tpublic void remove() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/IntentResolver.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.Build;\n\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\npublic abstract class IntentResolver<F extends VPackage.IntentInfo, R extends Object> {\n\n\tprivate static final String TAG = \"IntentResolver\";\n\n\t// Sorts a List of IntentFilter objects into descending priority order.\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate static final Comparator sResolvePrioritySorter = new Comparator() {\n\t\tpublic int compare(Object o1, Object o2) {\n\t\t\tint q1;\n\t\t\tint q2;\n\t\t\tif (o1 instanceof IntentFilter) {\n\t\t\t\tq1 = ((IntentFilter) o1).getPriority();\n\t\t\t\tq2 = ((IntentFilter) o2).getPriority();\n\t\t\t} else if (o1 instanceof ResolveInfo) {\n\t\t\t\tResolveInfo r1 = (ResolveInfo) o1;\n\t\t\t\tResolveInfo r2 = (ResolveInfo) o2;\n\t\t\t\tq1 = r1.filter == null ? 0 : r1.filter.getPriority();\n\t\t\t\tq2 = r2.filter == null ? 0 : r2.filter.getPriority();\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);\n\t\t}\n\t};\n\t/**\n\t * All filters that have been registered.\n\t */\n\tprivate HashSet<F> mFilters = new HashSet<F>();\n\t/**\n\t * All of the MIME types that have been registered, such as \"image/jpeg\",\n\t * \"image/*\", or \"{@literal *}/*\".\n\t */\n\tprivate HashMap<String, F[]> mTypeToFilter = new HashMap<String, F[]>();\n\t/**\n\t * The base names of all of all fully qualified MIME types that have been\n\t * registered, such as \"image\" or \"*\". Wild card MIME types such as\n\t * \"image/*\" will not be here.\n\t */\n\tprivate HashMap<String, F[]> mBaseTypeToFilter = new HashMap<String, F[]>();\n\t/**\n\t * The base names of all of the MIME types with a sub-type wildcard that\n\t * have been registered. For example, a filter with \"image/*\" will be\n\t * included here as \"image\" but one with \"image/jpeg\" will not be included\n\t * here. This also includes the \"*\" for the \"{@literal *}/*\" MIME type.\n\t */\n\tprivate HashMap<String, F[]> mWildTypeToFilter = new HashMap<String, F[]>();\n\t/**\n\t * All of the URI schemes (such as http) that have been registered.\n\t */\n\tprivate HashMap<String, F[]> mSchemeToFilter = new HashMap<String, F[]>();\n\t/**\n\t * All of the actions that have been registered, but only those that did not\n\t * specify data.\n\t */\n\tprivate HashMap<String, F[]> mActionToFilter = new HashMap<String, F[]>();\n\t/**\n\t * All of the actions that have been registered and specified a MIME type.\n\t */\n\tprivate HashMap<String, F[]> mTypedActionToFilter = new HashMap<String, F[]>();\n\n\tprivate static FastImmutableArraySet<String> getFastIntentCategories(Intent intent) {\n\t\tfinal Set<String> categories = intent.getCategories();\n\t\tif (categories == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new FastImmutableArraySet<String>(categories.toArray(new String[categories.size()]));\n\t}\n\n\tpublic void addFilter(F f) {\n\n\t\tmFilters.add(f);\n\t\tint numS = register_intent_filter(f, f.filter.schemesIterator(), mSchemeToFilter, \"      Scheme: \");\n\t\tint numT = register_mime_types(f, \"      Type: \");\n\t\tif (numS == 0 && numT == 0) {\n\t\t\tregister_intent_filter(f, f.filter.actionsIterator(), mActionToFilter, \"      Action: \");\n\t\t}\n\t\tif (numT != 0) {\n\t\t\tregister_intent_filter(f, f.filter.actionsIterator(), mTypedActionToFilter, \"      TypedAction: \");\n\t\t}\n\t}\n\n\tprivate boolean filterEquals(IntentFilter f1, IntentFilter f2) {\n\t\tint s1 = f1.countActions();\n\t\tint s2 = f2.countActions();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (int i = 0; i < s1; i++) {\n\t\t\tif (!f2.hasAction(f1.getAction(i))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\ts1 = f1.countCategories();\n\t\ts2 = f2.countCategories();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (int i = 0; i < s1; i++) {\n\t\t\tif (!f2.hasCategory(f1.getCategory(i))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\ts1 = f1.countDataTypes();\n\t\ts2 = f2.countDataTypes();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\ts1 = f1.countDataSchemes();\n\t\ts2 = f2.countDataSchemes();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (int i = 0; i < s1; i++) {\n\t\t\tif (!f2.hasDataScheme(f1.getDataScheme(i))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\ts1 = f1.countDataAuthorities();\n\t\ts2 = f2.countDataAuthorities();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\ts1 = f1.countDataPaths();\n\t\ts2 = f2.countDataPaths();\n\t\tif (s1 != s2) {\n\t\t\treturn false;\n\t\t}\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n\t\t\ts1 = f1.countDataSchemeSpecificParts();\n\t\t\ts2 = f2.countDataSchemeSpecificParts();\n\t\t\tif (s1 != s2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate ArrayList<F> collectFilters(F[] array, IntentFilter matching) {\n\t\tArrayList<F> res = null;\n\t\tif (array != null) {\n\t\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\t\tF cur = array[i];\n\t\t\t\tif (cur == null) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (filterEquals(cur.filter, matching)) {\n\t\t\t\t\tif (res == null) {\n\t\t\t\t\t\tres = new ArrayList<>();\n\t\t\t\t\t}\n\t\t\t\t\tres.add(cur);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn res;\n\t}\n\n\tpublic ArrayList<F> findFilters(IntentFilter matching) {\n\t\tif (matching.countDataSchemes() == 1) {\n\t\t\t// Fast case.\n\t\t\treturn collectFilters(mSchemeToFilter.get(matching.getDataScheme(0)), matching);\n\t\t} else if (matching.countDataTypes() != 0 && matching.countActions() == 1) {\n\t\t\t// Another fast case.\n\t\t\treturn collectFilters(mTypedActionToFilter.get(matching.getAction(0)), matching);\n\t\t} else if (matching.countDataTypes() == 0 && matching.countDataSchemes() == 0 && matching.countActions() == 1) {\n\t\t\t// Last fast case.\n\t\t\treturn collectFilters(mActionToFilter.get(matching.getAction(0)), matching);\n\t\t} else {\n\t\t\tArrayList<F> res = null;\n\t\t\tfor (F cur : mFilters) {\n\t\t\t\tif (filterEquals(cur.filter, matching)) {\n\t\t\t\t\tif (res == null) {\n\t\t\t\t\t\tres = new ArrayList<>();\n\t\t\t\t\t}\n\t\t\t\t\tres.add(cur);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t}\n\t}\n\n\tpublic void removeFilter(F f) {\n\t\tremoveFilterInternal(f);\n\t\tmFilters.remove(f);\n\t}\n\n\tvoid removeFilterInternal(F f) {\n\n\t\tint numS = unregister_intent_filter(f, f.filter.schemesIterator(), mSchemeToFilter, \"      Scheme: \");\n\t\tint numT = unregister_mime_types(f, \"      Type: \");\n\t\tif (numS == 0 && numT == 0) {\n\t\t\tunregister_intent_filter(f, f.filter.actionsIterator(), mActionToFilter, \"      Action: \");\n\t\t}\n\t\tif (numT != 0) {\n\t\t\tunregister_intent_filter(f, f.filter.actionsIterator(), mTypedActionToFilter, \"      TypedAction: \");\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator allowing filters to be removed.\n\t */\n\tpublic Iterator<F> filterIterator() {\n\t\treturn new IteratorWrapper(mFilters.iterator());\n\t}\n\n\t/**\n\t * Returns a read-only set of the filters.\n\t */\n\tpublic Set<F> filterSet() {\n\t\treturn Collections.unmodifiableSet(mFilters);\n\t}\n\n\tpublic List<R> queryIntentFromList(Intent intent, String resolvedType, boolean defaultOnly,\n\t\t\tArrayList<F[]> listCut, int userId) {\n\t\tArrayList<R> resultList = new ArrayList<R>();\n\t\tFastImmutableArraySet<String> categories = getFastIntentCategories(intent);\n\t\tfinal String scheme = intent.getScheme();\n\t\tint N = listCut.size();\n\t\tfor (int i = 0; i < N; ++i) {\n\t\t\tbuildResolveList(intent, categories, defaultOnly, resolvedType, scheme, listCut.get(i), resultList, userId);\n\t\t}\n\t\tsortResults(resultList);\n\t\treturn resultList;\n\t}\n\n\tpublic List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {\n\t\tString scheme = intent.getScheme();\n\n\t\tArrayList<R> finalList = new ArrayList<R>();\n\t\tF[] firstTypeCut = null;\n\t\tF[] secondTypeCut = null;\n\t\tF[] thirdTypeCut = null;\n\t\tF[] schemeCut = null;\n\n\t\t// If the intent includes a MIME type, then we want to collect all of\n\t\t// the filters that match that MIME type.\n\t\tif (resolvedType != null) {\n\t\t\tint slashpos = resolvedType.indexOf('/');\n\t\t\tif (slashpos > 0) {\n\t\t\t\tfinal String baseType = resolvedType.substring(0, slashpos);\n\t\t\t\tif (!baseType.equals(\"*\")) {\n\t\t\t\t\tif (resolvedType.length() != slashpos + 2 || resolvedType.charAt(slashpos + 1) != '*') {\n\t\t\t\t\t\t// Not a wild card, so we can just look for all filters\n\t\t\t\t\t\t// that\n\t\t\t\t\t\t// completely match or wildcards whose base type\n\t\t\t\t\t\t// matches.\n\t\t\t\t\t\tfirstTypeCut = mTypeToFilter.get(resolvedType);\n\t\t\t\t\t\tsecondTypeCut = mWildTypeToFilter.get(baseType);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We can match anything with our base type.\n\t\t\t\t\t\tfirstTypeCut = mBaseTypeToFilter.get(baseType);\n\t\t\t\t\t\tsecondTypeCut = mWildTypeToFilter.get(baseType);\n\t\t\t\t\t}\n\t\t\t\t\t// Any */* types always apply, but we only need to do this\n\t\t\t\t\t// if the intent type was not already */*.\n\t\t\t\t\tthirdTypeCut = mWildTypeToFilter.get(\"*\");\n\t\t\t\t} else if (intent.getAction() != null) {\n\t\t\t\t\t// The intent specified any type ({@literal *}/*). This\n\t\t\t\t\t// can be a whole heck of a lot of things, so as a first\n\t\t\t\t\t// cut let's use the action instead.\n\t\t\t\t\tfirstTypeCut = mTypedActionToFilter.get(intent.getAction());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If the intent includes a data URI, then we want to collect all of\n\t\t// the filters that match its scheme (we will further refine matches\n\t\t// on the authority and path by directly matching each resulting\n\t\t// filter).\n\t\tif (scheme != null) {\n\t\t\tschemeCut = mSchemeToFilter.get(scheme);\n\t\t}\n\n\t\t// If the intent does not specify any data -- either a MIME type or\n\t\t// a URI -- then we will only be looking for matches against empty\n\t\t// data.\n\t\tif (resolvedType == null && scheme == null && intent.getAction() != null) {\n\t\t\tfirstTypeCut = mActionToFilter.get(intent.getAction());\n\t\t}\n\n\t\tFastImmutableArraySet<String> categories = getFastIntentCategories(intent);\n\t\tif (firstTypeCut != null) {\n\t\t\tbuildResolveList(intent, categories, defaultOnly, resolvedType, scheme, firstTypeCut, finalList, userId);\n\t\t}\n\t\tif (secondTypeCut != null) {\n\t\t\tbuildResolveList(intent, categories, defaultOnly, resolvedType, scheme, secondTypeCut, finalList, userId);\n\t\t}\n\t\tif (thirdTypeCut != null) {\n\t\t\tbuildResolveList(intent, categories, defaultOnly, resolvedType, scheme, thirdTypeCut, finalList, userId);\n\t\t}\n\t\tif (schemeCut != null) {\n\t\t\tbuildResolveList(intent, categories, defaultOnly, resolvedType, scheme, schemeCut, finalList, userId);\n\t\t}\n\t\tsortResults(finalList);\n\t\treturn finalList;\n\t}\n\n\t/**\n\t * Control whether the given filter is allowed to go into the result list.\n\t * Mainly intended to prevent adding multiple filters for the same target\n\t * object.\n\t */\n\tprotected boolean allowFilterResult(F filter, List<R> dest) {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns whether the object associated with the given filter is \"stopped\",\n\t * that is whether it should not be included in the result if the intent\n\t * requests to excluded stopped objects.\n\t */\n\tprotected boolean isFilterStopped(F filter) {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns whether this filter is owned by this package. This must be\n\t * implemented to provide correct filtering of Intents that have specified a\n\t * package name they are to be delivered to.\n\t */\n\tprotected abstract boolean isPackageForFilter(String packageName, F filter);\n\n\tprotected abstract F[] newArray(int size);\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected R newResult(F filter, int match, int userId) {\n\t\treturn (R) filter;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected void sortResults(List<R> results) {\n\t\tCollections.sort(results, sResolvePrioritySorter);\n\t}\n\n\tprotected void dumpFilter(PrintWriter out, String prefix, F filter) {\n\t\tout.print(prefix);\n\t\tout.println(filter);\n\t}\n\n\tprotected Object filterToLabel(F filter) {\n\t\treturn \"IntentFilter\";\n\t}\n\n\tprotected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {\n\t\tout.print(prefix);\n\t\tout.print(label);\n\t\tout.print(\": \");\n\t\tout.println(count);\n\t}\n\n\tprivate void addFilter(HashMap<String, F[]> map, String name, F filter) {\n\t\tF[] array = map.get(name);\n\t\tif (array == null) {\n\t\t\tarray = newArray(2);\n\t\t\tmap.put(name, array);\n\t\t\tarray[0] = filter;\n\t\t} else {\n\t\t\tfinal int N = array.length;\n\t\t\tint i = N;\n\t\t\twhile (i > 0 && array[i - 1] == null) {\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif (i < N) {\n\t\t\t\tarray[i] = filter;\n\t\t\t} else {\n\t\t\t\tF[] newa = newArray((N * 3) / 2);\n\t\t\t\tSystem.arraycopy(array, 0, newa, 0, N);\n\t\t\t\tnewa[N] = filter;\n\t\t\t\tmap.put(name, newa);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate int register_mime_types(F filter, String prefix) {\n\t\tfinal Iterator<String> i = filter.filter.typesIterator();\n\t\tif (i == null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tint num = 0;\n\t\twhile (i.hasNext()) {\n\t\t\tString name = i.next();\n\t\t\tnum++;\n\t\t\tString baseName = name;\n\t\t\tfinal int slashpos = name.indexOf('/');\n\t\t\tif (slashpos > 0) {\n\t\t\t\tbaseName = name.substring(0, slashpos).intern();\n\t\t\t} else {\n\t\t\t\tname = name + \"/*\";\n\t\t\t}\n\n\t\t\taddFilter(mTypeToFilter, name, filter);\n\n\t\t\tif (slashpos > 0) {\n\t\t\t\taddFilter(mBaseTypeToFilter, baseName, filter);\n\t\t\t} else {\n\t\t\t\taddFilter(mWildTypeToFilter, baseName, filter);\n\t\t\t}\n\t\t}\n\n\t\treturn num;\n\t}\n\n\tprivate int unregister_mime_types(F filter, String prefix) {\n\t\tfinal Iterator<String> i = filter.filter.typesIterator();\n\t\tif (i == null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tint num = 0;\n\t\twhile (i.hasNext()) {\n\t\t\tString name = i.next();\n\t\t\tnum++;\n\t\t\tString baseName = name;\n\t\t\tfinal int slashpos = name.indexOf('/');\n\t\t\tif (slashpos > 0) {\n\t\t\t\tbaseName = name.substring(0, slashpos).intern();\n\t\t\t} else {\n\t\t\t\tname = name + \"/*\";\n\t\t\t}\n\n\t\t\tremove_all_objects(mTypeToFilter, name, filter);\n\n\t\t\tif (slashpos > 0) {\n\t\t\t\tremove_all_objects(mBaseTypeToFilter, baseName, filter);\n\t\t\t} else {\n\t\t\t\tremove_all_objects(mWildTypeToFilter, baseName, filter);\n\t\t\t}\n\t\t}\n\t\treturn num;\n\t}\n\n\tprivate int register_intent_filter(F filter, Iterator<String> i, HashMap<String, F[]> dest, String prefix) {\n\t\tif (i == null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tint num = 0;\n\t\twhile (i.hasNext()) {\n\t\t\tString name = i.next();\n\t\t\tnum++;\n\t\t\taddFilter(dest, name, filter);\n\t\t}\n\t\treturn num;\n\t}\n\n\tprivate int unregister_intent_filter(F filter, Iterator<String> i, HashMap<String, F[]> dest, String prefix) {\n\t\tif (i == null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tint num = 0;\n\t\twhile (i.hasNext()) {\n\t\t\tString name = i.next();\n\t\t\tnum++;\n\t\t\tremove_all_objects(dest, name, filter);\n\t\t}\n\t\treturn num;\n\t}\n\n\tprivate void remove_all_objects(HashMap<String, F[]> map, String name, Object object) {\n\t\tF[] array = map.get(name);\n\t\tif (array != null) {\n\t\t\tint LAST = array.length - 1;\n\t\t\twhile (LAST >= 0 && array[LAST] == null) {\n\t\t\t\tLAST--;\n\t\t\t}\n\t\t\tfor (int idx = LAST; idx >= 0; idx--) {\n\t\t\t\tif (array[idx] == object) {\n\t\t\t\t\tfinal int remain = LAST - idx;\n\t\t\t\t\tif (remain > 0) {\n\t\t\t\t\t\tSystem.arraycopy(array, idx + 1, array, idx, remain);\n\t\t\t\t\t}\n\t\t\t\t\tarray[LAST] = null;\n\t\t\t\t\tLAST--;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (LAST < 0) {\n\t\t\t\tmap.remove(name);\n\t\t\t} else if (LAST < (array.length / 2)) {\n\t\t\t\tF[] newa = newArray(LAST + 2);\n\t\t\t\tSystem.arraycopy(array, 0, newa, 0, LAST + 1);\n\t\t\t\tmap.put(name, newa);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,\n\t\t\t\t\t\t\t\t  boolean defaultOnly, String resolvedType, String scheme, F[] src, List<R> dest, int userId) {\n\t\tfinal String action = intent.getAction();\n\t\tfinal Uri data = intent.getData();\n\t\tfinal String packageName = intent.getPackage();\n\n\t\tfinal int N = src != null ? src.length : 0;\n\t\tboolean hasNonDefaults = false;\n\t\tint i;\n\t\tF filter;\n\t\tfor (i = 0; i < N && (filter = src[i]) != null; i++) {\n\t\t\tint match;\n\n\t\t\t// Is delivery being limited to filters owned by a particular\n\t\t\t// package?\n\t\t\tif (packageName != null && !isPackageForFilter(packageName, filter)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Do we already have this one?\n\t\t\tif (!allowFilterResult(filter, dest)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmatch = filter.filter.match(action, resolvedType, scheme, data, categories, TAG);\n\t\t\tif (match >= 0) {\n\t\t\t\tif (!defaultOnly || filter.filter.hasCategory(Intent.CATEGORY_DEFAULT)) {\n\t\t\t\t\tfinal R oneResult = newResult(filter, match, userId);\n\t\t\t\t\tif (oneResult != null) {\n\t\t\t\t\t\tdest.add(oneResult);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\thasNonDefaults = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (hasNonDefaults) {\n\t\t\tif (dest.size() == 0) {\n\t\t\t\tVLog.w(TAG, \"resolveIntent failed: found match, but none with CATEGORY_DEFAULT\");\n\t\t\t} else if (dest.size() > 1) {\n\t\t\t\tVLog.w(TAG, \"resolveIntent: multiple matches, only some with CATEGORY_DEFAULT\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate class IteratorWrapper implements Iterator<F> {\n\t\tprivate Iterator<F> mI;\n\t\tprivate F mCur;\n\n\t\tIteratorWrapper(Iterator<F> it) {\n\t\t\tmI = it;\n\t\t}\n\n\t\tpublic boolean hasNext() {\n\t\t\treturn mI.hasNext();\n\t\t}\n\n\t\tpublic F next() {\n\t\t\treturn (mCur = mI.next());\n\t\t}\n\n\t\tpublic void remove() {\n\t\t\tif (mCur != null) {\n\t\t\t\tremoveFilterInternal(mCur);\n\t\t\t}\n\t\t\tmI.remove();\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PackageCacheManager.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.server.pm.parser.PackageParserEx;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\n/**\n * @author Lody\n */\n\npublic class PackageCacheManager {\n\n    static final ArrayMap<String, VPackage> PACKAGE_CACHE = new ArrayMap<>();\n\n    public static int size() {\n        synchronized (PACKAGE_CACHE) {\n            return PACKAGE_CACHE.size();\n        }\n    }\n\n    public static void put(VPackage pkg, PackageSetting ps) {\n        synchronized (PackageCacheManager.class) {\n            PackageParserEx.initApplicationInfoBase(ps, pkg);\n            PACKAGE_CACHE.put(pkg.packageName, pkg);\n            pkg.mExtras = ps;\n            VPackageManagerService.get().analyzePackageLocked(pkg);\n        }\n    }\n\n    public static VPackage get(String packageName) {\n        synchronized (PackageCacheManager.class) {\n            return PACKAGE_CACHE.get(packageName);\n        }\n    }\n\n    public static PackageSetting getSetting(String packageName) {\n        synchronized (PackageCacheManager.class) {\n            VPackage p = PACKAGE_CACHE.get(packageName);\n            if (p != null) {\n                return (PackageSetting) p.mExtras;\n            }\n            return null;\n        }\n    }\n\n    public static VPackage remove(String packageName) {\n        synchronized (PackageCacheManager.class) {\n            VPackageManagerService.get().deletePackageLocked(packageName);\n            return PACKAGE_CACHE.remove(packageName);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PackagePersistenceLayer.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.os.Parcel;\n\nimport com.lody.virtual.helper.PersistenceLayer;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.util.Arrays;\n\n/**\n * @author Lody\n */\n\nclass PackagePersistenceLayer extends PersistenceLayer {\n\n    private static final char[] MAGIC = {'v', 'p', 'k', 'g'};\n    private static final int CURRENT_VERSION = 3;\n\n    private VAppManagerService mService;\n\n    PackagePersistenceLayer(VAppManagerService service) {\n        super(VEnvironment.getPackageListFile());\n        mService = service;\n    }\n\n    @Override\n    public int getCurrentVersion() {\n        return CURRENT_VERSION;\n    }\n\n    @Override\n    public void writeMagic(Parcel p) {\n        p.writeCharArray(MAGIC);\n    }\n\n    @Override\n    public boolean verifyMagic(Parcel p) {\n        char[] magic = p.createCharArray();\n        return Arrays.equals(magic, MAGIC);\n    }\n\n\n    @Override\n    public void writePersistenceData(Parcel p) {\n        synchronized (PackageCacheManager.PACKAGE_CACHE) {\n            p.writeInt(PackageCacheManager.PACKAGE_CACHE.size());\n            for (VPackage pkg : PackageCacheManager.PACKAGE_CACHE.values()) {\n                PackageSetting ps = (PackageSetting) pkg.mExtras;\n                ps.writeToParcel(p, 0);\n            }\n        }\n    }\n\n    @Override\n    public void readPersistenceData(Parcel p) {\n        int count = p.readInt();\n        while (count-- > 0) {\n            PackageSetting setting = new PackageSetting(p);\n            mService.loadPackage(setting);\n        }\n    }\n\n    @Override\n    public boolean onVersionConflict(int fileVersion, int currentVersion) {\n        // I am so lazy to process it...\n        return false;\n    }\n\n    @Override\n    public void onPersistenceFileDamage() {\n        getPersistenceFile().delete();\n        VAppManagerService.get().restoreFactoryState();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PackageSetting.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.remote.InstalledAppInfo;\n\n/**\n * @author Lody\n */\n\npublic class PackageSetting implements Parcelable {\n\n    public static final Parcelable.Creator<PackageSetting> CREATOR = new Parcelable.Creator<PackageSetting>() {\n        @Override\n        public PackageSetting createFromParcel(Parcel source) {\n            return new PackageSetting(source);\n        }\n\n        @Override\n        public PackageSetting[] newArray(int size) {\n            return new PackageSetting[size];\n        }\n    };\n    private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();\n    public String packageName;\n    public String apkPath;\n    public String libPath;\n    public boolean dependSystem;\n    @Deprecated\n    public boolean skipDexOpt;\n    public int appId;\n    public long firstInstallTime;\n    public long lastUpdateTime;\n\n    public String[] splitCodePaths;\n    private SparseArray<PackageUserState> userState = new SparseArray<>();\n\n    public PackageSetting() {\n    }\n\n    protected PackageSetting(Parcel in) {\n        this.packageName = in.readString();\n        this.apkPath = in.readString();\n        this.libPath = in.readString();\n        this.dependSystem = in.readByte() != 0;\n        this.appId = in.readInt();\n        //noinspection unchecked\n        this.userState = in.readSparseArray(PackageUserState.class.getClassLoader());\n        this.skipDexOpt = in.readByte() != 0;\n        this.splitCodePaths = in.createStringArray();\n    }\n\n    public InstalledAppInfo getAppInfo() {\n        return new InstalledAppInfo(packageName, apkPath, libPath, dependSystem, skipDexOpt, appId, splitCodePaths);\n    }\n\n    PackageUserState modifyUserState(int userId) {\n        PackageUserState state = userState.get(userId);\n        if (state == null) {\n            state = new PackageUserState();\n            userState.put(userId, state);\n        }\n        return state;\n    }\n\n    void setUserState(int userId, boolean launched, boolean hidden, boolean installed) {\n        PackageUserState state = modifyUserState(userId);\n        state.launched = launched;\n        state.hidden = hidden;\n        state.installed = installed;\n    }\n\n    PackageUserState readUserState(int userId) {\n        PackageUserState state = userState.get(userId);\n        if (state != null) {\n            return state;\n        }\n        return DEFAULT_USER_STATE;\n    }\n\n    void removeUser(int userId) {\n        userState.delete(userId);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(this.packageName);\n        dest.writeString(this.apkPath);\n        dest.writeString(this.libPath);\n        dest.writeByte(this.dependSystem ? (byte) 1 : (byte) 0);\n        dest.writeInt(this.appId);\n        //noinspection unchecked\n        dest.writeSparseArray((SparseArray) this.userState);\n        dest.writeByte(this.skipDexOpt ? (byte) 1 : (byte) 0);\n        dest.writeStringArray(this.splitCodePaths);\n    }\n\n    public boolean isLaunched(int userId) {\n        return readUserState(userId).launched;\n    }\n\n    public boolean isHidden(int userId) {\n        return readUserState(userId).hidden;\n    }\n\n    public boolean isInstalled(int userId) {\n        return readUserState(userId).installed;\n    }\n\n    public void setLaunched(int userId, boolean launched) {\n        modifyUserState(userId).launched = launched;\n    }\n\n    public void setHidden(int userId, boolean hidden) {\n        modifyUserState(userId).hidden = hidden;\n    }\n\n    public void setInstalled(int userId, boolean installed) {\n        modifyUserState(userId).installed = installed;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PackageUserState.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n */\n\npublic class PackageUserState implements Parcelable {\n\n    public static final Parcelable.Creator<PackageUserState> CREATOR = new Parcelable.Creator<PackageUserState>() {\n        @Override\n        public PackageUserState createFromParcel(Parcel source) {\n            return new PackageUserState(source);\n        }\n\n        @Override\n        public PackageUserState[] newArray(int size) {\n            return new PackageUserState[size];\n        }\n    };\n    public boolean launched;\n    public boolean hidden;\n    public boolean installed;\n\n    public PackageUserState() {\n        installed = false;\n        launched = true;\n        hidden = false;\n    }\n\n    protected PackageUserState(Parcel in) {\n        this.launched = in.readByte() != 0;\n        this.hidden = in.readByte() != 0;\n        this.installed = in.readByte() != 0;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeByte(this.launched ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.hidden ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.installed ? (byte) 1 : (byte) 0);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/PrivilegeAppOptimizer.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.content.Intent;\n\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.server.am.VActivityManagerService;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * @author Lody\n */\n\npublic class PrivilegeAppOptimizer {\n\n    private static final PrivilegeAppOptimizer sInstance = new PrivilegeAppOptimizer();\n    private final List<String> privilegeApps = new ArrayList<>();\n\n    private PrivilegeAppOptimizer() {\n        Collections.addAll(privilegeApps, VASettings.PRIVILEGE_APPS);\n    }\n\n    public static PrivilegeAppOptimizer get() {\n        return sInstance;\n    }\n\n    public List<String> getPrivilegeApps() {\n        return Collections.unmodifiableList(privilegeApps);\n    }\n\n    public void addPrivilegeApp(String packageName) {\n        privilegeApps.add(packageName);\n    }\n\n    public void removePrivilegeApp(String packageName) {\n        privilegeApps.remove(packageName);\n    }\n\n    public boolean isPrivilegeApp(String packageName) {\n        return privilegeApps.contains(packageName);\n    }\n\n    public void performOptimizeAllApps() {\n        for (String pkg : privilegeApps) {\n            performOptimize(pkg, VUserHandle.USER_ALL);\n        }\n    }\n\n    public boolean performOptimize(String packageName, int userId) {\n        VActivityManagerService.get().sendBroadcastAsUser(\n                specifyApp(new Intent(Intent.ACTION_BOOT_COMPLETED), packageName, userId)\n                , new VUserHandle(userId));\n        return true;\n    }\n\n    public static void notifyBootFinish() {\n        for (String pkg : Constants.PRIVILEGE_APP) {\n            try {\n                PrivilegeAppOptimizer.get().performOptimize(pkg, 0);\n            } catch (Throwable ignored) {\n            }\n        }\n    }\n\n    private Intent specifyApp(Intent intent, String packageName, int userId) {\n        intent.putExtra(\"_VA_|_privilege_pkg_\", packageName);\n        intent.putExtra(\"_VA_|_user_id_\", userId);\n        intent.putExtra(\"_VA_|_intent_\", new Intent(Intent.ACTION_BOOT_COMPLETED));\n        return intent;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/ProviderIntentResolver.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.annotation.TargetApi;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.os.Build;\n\nimport com.lody.virtual.helper.compat.ObjectsCompat;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.server.pm.parser.PackageParserEx;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport static com.lody.virtual.server.pm.VPackageManagerService.TAG;\n\nfinal class ProviderIntentResolver extends IntentResolver<VPackage.ProviderIntentInfo, ResolveInfo> {\n    private final HashMap<ComponentName, VPackage.ProviderComponent> mProviders = new HashMap<>();\n    private int mFlags;\n\n    public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {\n        mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;\n        return super.queryIntent(intent, resolvedType, defaultOnly, userId);\n    }\n\n    public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) {\n        mFlags = flags;\n        return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);\n    }\n\n    public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags,\n                                                   ArrayList<VPackage.ProviderComponent> packageProviders, int userId) {\n        if (packageProviders == null) {\n            return null;\n        }\n        mFlags = flags;\n        final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;\n        final int N = packageProviders.size();\n        ArrayList<VPackage.ProviderIntentInfo[]> listCut = new ArrayList<>(N);\n\n        ArrayList<VPackage.ProviderIntentInfo> intentFilters;\n        for (int i = 0; i < N; ++i) {\n            intentFilters = packageProviders.get(i).intents;\n            if (intentFilters != null && intentFilters.size() > 0) {\n                VPackage.ProviderIntentInfo[] array = new VPackage.ProviderIntentInfo[intentFilters\n                        .size()];\n                intentFilters.toArray(array);\n                listCut.add(array);\n            }\n        }\n        return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);\n    }\n\n    public final void addProvider(VPackage.ProviderComponent p) {\n        if (mProviders.containsKey(p.getComponentName())) {\n            VLog.w(TAG, \"Provider \" + p.getComponentName() + \" already defined; ignoring\");\n            return;\n        }\n\n        mProviders.put(p.getComponentName(), p);\n        final int NI = p.intents.size();\n        int j;\n        for (j = 0; j < NI; j++) {\n            VPackage.ProviderIntentInfo intent = p.intents.get(j);\n            addFilter(intent);\n        }\n    }\n\n    public final void removeProvider(VPackage.ProviderComponent p) {\n        mProviders.remove(p.getComponentName());\n        final int NI = p.intents.size();\n        int j;\n        for (j = 0; j < NI; j++) {\n            VPackage.ProviderIntentInfo intent = p.intents.get(j);\n            removeFilter(intent);\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    @Override\n    protected boolean allowFilterResult(VPackage.ProviderIntentInfo filter, List<ResolveInfo> dest) {\n        ProviderInfo filterPi = filter.provider.info;\n        for (int i = dest.size() - 1; i >= 0; i--) {\n            ProviderInfo destPi = dest.get(i).providerInfo;\n            if (ObjectsCompat.equals(destPi.name, filterPi.name)\n                    && ObjectsCompat.equals(destPi.packageName, filterPi.packageName)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    protected VPackage.ProviderIntentInfo[] newArray(int size) {\n        return new VPackage.ProviderIntentInfo[size];\n    }\n\n    @Override\n    protected boolean isFilterStopped(VPackage.ProviderIntentInfo filter) {\n        return false;\n    }\n\n    @Override\n    protected boolean isPackageForFilter(String packageName, VPackage.ProviderIntentInfo info) {\n        return packageName.equals(info.provider.owner.packageName);\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    @Override\n    protected ResolveInfo newResult(VPackage.ProviderIntentInfo filter, int match, int userId) {\n        final VPackage.ProviderComponent provider = filter.provider;\n        PackageSetting ps = (PackageSetting) provider.owner.mExtras;\n        ProviderInfo pi = PackageParserEx.generateProviderInfo(provider, mFlags, ps.readUserState(userId), userId);\n        if (pi == null) {\n            return null;\n        }\n        final ResolveInfo res = new ResolveInfo();\n        res.providerInfo = pi;\n        if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {\n            res.filter = filter.filter;\n        }\n        res.priority = filter.filter.getPriority();\n        res.preferredOrder = provider.owner.mPreferredOrder;\n        res.match = match;\n        res.isDefault = filter.hasDefault;\n        res.labelRes = filter.labelRes;\n        res.nonLocalizedLabel = filter.nonLocalizedLabel;\n        res.icon = filter.icon;\n        return res;\n    }\n\n    @Override\n    protected void sortResults(List<ResolveInfo> results) {\n        Collections.sort(results, VPackageManagerService.sResolvePrioritySorter);\n    }\n\n    @Override\n    protected void dumpFilter(PrintWriter out, String prefix, VPackage.ProviderIntentInfo filter) {\n\n    }\n\n    @Override\n    protected Object filterToLabel(VPackage.ProviderIntentInfo filter) {\n        return filter.provider;\n    }\n\n    protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {\n\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VAppManagerService.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.client.core.InstallStrategy;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.collection.IntArray;\nimport com.lody.virtual.helper.compat.NativeLibraryHelperCompat;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.InstallResult;\nimport com.lody.virtual.remote.InstalledAppInfo;\nimport com.lody.virtual.server.IAppManager;\nimport com.lody.virtual.server.accounts.VAccountManagerService;\nimport com.lody.virtual.server.am.BroadcastSystem;\nimport com.lody.virtual.server.am.UidSystem;\nimport com.lody.virtual.server.am.VActivityManagerService;\nimport com.lody.virtual.server.interfaces.IAppRequestListener;\nimport com.lody.virtual.server.interfaces.IPackageObserver;\nimport com.lody.virtual.server.pm.parser.PackageParserEx;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * @author Lody\n */\npublic class VAppManagerService extends IAppManager.Stub {\n\n    private static final String TAG = VAppManagerService.class.getSimpleName();\n    private static final AtomicReference<VAppManagerService> sService = new AtomicReference<>();\n    private final UidSystem mUidSystem = new UidSystem();\n    private final PackagePersistenceLayer mPersistenceLayer = new PackagePersistenceLayer(this);\n    private final Set<String> mVisibleOutsidePackages = new HashSet<>();\n    private boolean mBooting;\n    private RemoteCallbackList<IPackageObserver> mRemoteCallbackList = new RemoteCallbackList<>();\n    private IAppRequestListener mAppRequestListener;\n\n    public static VAppManagerService get() {\n        return sService.get();\n    }\n\n    public static void systemReady() {\n        VEnvironment.systemReady();\n        VAppManagerService instance = new VAppManagerService();\n        instance.mUidSystem.initUidList();\n        sService.set(instance);\n    }\n\n    public boolean isBooting() {\n        return mBooting;\n    }\n\n    @Override\n    public void scanApps() {\n        if (mBooting) {\n            return;\n        }\n        synchronized (this) {\n            mBooting = true;\n            mPersistenceLayer.read();\n            PrivilegeAppOptimizer.get().performOptimizeAllApps();\n            mBooting = false;\n        }\n    }\n\n    private void cleanUpResidualFiles(PackageSetting ps) {\n        VLog.w(TAG, \"cleanUpResidualFiles: \" + ps.packageName);\n        File dataAppDir = VEnvironment.getDataAppPackageDirectory(ps.packageName);\n        FileUtils.deleteDir(dataAppDir);\n\n        // We shouldn't remove user data here!!! Just remove the package.\n        // for (int userId : VUserManagerService.get().getUserIds()) {\n        //     FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(userId, ps.packageName));\n        // }\n    }\n\n\n    synchronized void loadPackage(PackageSetting setting) {\n        if (!loadPackageInnerLocked(setting)) {\n            cleanUpResidualFiles(setting);\n        }\n    }\n\n    private boolean loadPackageInnerLocked(PackageSetting ps) {\n        if (ps.dependSystem) {\n            if (!VirtualCore.get().isOutsideInstalled(ps.packageName)) {\n                return false;\n            }\n        }\n        File cacheFile = VEnvironment.getPackageCacheFile(ps.packageName);\n        VPackage pkg = null;\n        try {\n            pkg = PackageParserEx.readPackageCache(ps.packageName);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        if (pkg == null || pkg.packageName == null) {\n            return false;\n        }\n        chmodPackageDictionary(cacheFile);\n        PackageCacheManager.put(pkg, ps);\n        BroadcastSystem.get().startApp(pkg);\n        return true;\n    }\n\n    @Override\n    public boolean isOutsidePackageVisible(String pkg) {\n        return pkg != null && mVisibleOutsidePackages.contains(pkg);\n    }\n\n    @Override\n    public void addVisibleOutsidePackage(String pkg) {\n        if (pkg != null) {\n            mVisibleOutsidePackages.add(pkg);\n        }\n    }\n\n    @Override\n    public void removeVisibleOutsidePackage(String pkg) {\n        if (pkg != null) {\n            mVisibleOutsidePackages.remove(pkg);\n        }\n    }\n\n    @Override\n    public InstallResult installPackage(String path, int flags) {\n        return installPackage(path, flags, true);\n    }\n\n    public synchronized InstallResult installPackage(String path, int flags, boolean notify) {\n        long installTime = System.currentTimeMillis();\n        if (path == null) {\n            return InstallResult.makeFailure(\"path = NULL\");\n        }\n        File packageFile = new File(path);\n        if (!packageFile.exists()) {\n            return InstallResult.makeFailure(\"Package File is not exist.\");\n        }\n        VPackage pkg = null;\n        try {\n            pkg = PackageParserEx.parsePackage(packageFile);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        if (pkg == null || pkg.packageName == null) {\n            return InstallResult.makeFailure(\"Unable to parse the package.\");\n        }\n        InstallResult res = new InstallResult();\n        res.packageName = pkg.packageName;\n        // PackageCache holds all packages, try to check if we need to update.\n        VPackage existOne = PackageCacheManager.get(pkg.packageName);\n        PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null;\n        if (existOne != null) {\n            if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) {\n                res.isUpdate = true;\n                return res;\n            }\n            if (!canUpdate(existOne, pkg, flags)) {\n                return InstallResult.makeFailure(\"Can not update the package (such as version downrange).\");\n            }\n            res.isUpdate = true;\n        }\n        File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName);\n        File libDir = new File(appDir, \"lib\");\n        if (res.isUpdate) {\n            FileUtils.deleteDir(libDir);\n            VEnvironment.getOdexFile(pkg.packageName).delete();\n            VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL);\n        }\n        if (!libDir.exists() && !libDir.mkdirs()) {\n            return InstallResult.makeFailure(\"Unable to create lib dir.\");\n        }\n        boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0\n                && VirtualCore.get().isOutsideInstalled(pkg.packageName);\n\n        if (existSetting != null && existSetting.dependSystem) {\n            dependSystem = false;\n        }\n\n        String[] splitCodePaths = null;\n\n        if (!dependSystem) {\n            File privatePackageFile = new File(appDir, \"base.apk\");\n            File parentFolder = privatePackageFile.getParentFile();\n            if (!parentFolder.exists() && !parentFolder.mkdirs()) {\n                VLog.w(TAG, \"Warning: unable to create folder : \" + privatePackageFile.getPath());\n            } else if (privatePackageFile.exists() && !privatePackageFile.delete()) {\n                VLog.w(TAG, \"Warning: unable to delete file : \" + privatePackageFile.getPath());\n            }\n            File baseApkFile = packageFile.isFile() ? packageFile : new File(pkg.baseCodePath);\n            try {\n                FileUtils.copyFile(baseApkFile, privatePackageFile);\n            } catch (IOException e) {\n                privatePackageFile.delete();\n                return InstallResult.makeFailure(\"Unable to copy the package file.\");\n            }\n            // copy lib in base apk\n            NativeLibraryHelperCompat.copyNativeBinaries(baseApkFile, libDir);\n\n            packageFile = privatePackageFile;\n\n            if (pkg.splitNames != null) {\n                int length = pkg.splitNames.length;\n                splitCodePaths = new String[length];\n\n                for (int i = 0; i < length; i++) {\n                    String splitName = pkg.splitNames[i];\n                    File privateSplitFile = new File(appDir, splitName + \".apk\");\n                    try {\n                        FileUtils.copyFile(new File(pkg.splitCodePaths[i]), privateSplitFile);\n\n                        // copy lib in split apk\n                        NativeLibraryHelperCompat.copyNativeBinaries(privateSplitFile, libDir);\n                    } catch (IOException e) {\n                        privateSplitFile.delete();\n                        return InstallResult.makeFailure(\"Unable to copy split: \" + splitName);\n                    }\n                    splitCodePaths[i] = privateSplitFile.getPath();\n                }\n            }\n        }\n\n        if (existOne != null) {\n            PackageCacheManager.remove(pkg.packageName);\n        }\n        chmodPackageDictionary(packageFile);\n        PackageSetting ps;\n        if (existSetting != null) {\n            ps = existSetting;\n        } else {\n            ps = new PackageSetting();\n        }\n        ps.dependSystem = dependSystem;\n        ps.apkPath = packageFile.getPath();\n        ps.libPath = libDir.getPath();\n        ps.packageName = pkg.packageName;\n        ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));\n        if (res.isUpdate) {\n            ps.lastUpdateTime = installTime;\n        } else {\n            ps.firstInstallTime = installTime;\n            ps.lastUpdateTime = installTime;\n            for (int userId : VUserManagerService.get().getUserIds()) {\n                boolean installed = userId == 0;\n                ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);\n            }\n        }\n        ps.splitCodePaths = splitCodePaths;\n        PackageParserEx.savePackageCache(pkg);\n        PackageCacheManager.put(pkg, ps);\n        mPersistenceLayer.save();\n        BroadcastSystem.get().startApp(pkg);\n        if (notify) {\n            notifyAppInstalled(ps, -1);\n        }\n        res.isSuccess = true;\n        return res;\n    }\n\n\n    @Override\n    public synchronized boolean installPackageAsUser(int userId, String packageName) {\n        if (VUserManagerService.get().exists(userId)) {\n            PackageSetting ps = PackageCacheManager.getSetting(packageName);\n            if (ps != null) {\n                if (!ps.isInstalled(userId)) {\n                    ps.setInstalled(userId, true);\n                    notifyAppInstalled(ps, userId);\n                    mPersistenceLayer.save();\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private void chmodPackageDictionary(File packageFile) {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                if (FileUtils.isSymlink(packageFile)) {\n                    return;\n                }\n                FileUtils.chmod(packageFile.getParentFile().getAbsolutePath(), FileUtils.FileMode.MODE_755);\n                FileUtils.chmod(packageFile.getAbsolutePath(), FileUtils.FileMode.MODE_755);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private boolean canUpdate(VPackage existOne, VPackage newOne, int flags) {\n        if ((flags & InstallStrategy.COMPARE_VERSION) != 0) {\n            if (existOne.mVersionCode < newOne.mVersionCode) {\n                return true;\n            }\n        }\n        if ((flags & InstallStrategy.TERMINATE_IF_EXIST) != 0) {\n            return false;\n        }\n        if ((flags & InstallStrategy.UPDATE_IF_EXIST) != 0) {\n            return true;\n        }\n        return false;\n    }\n\n\n    @Override\n    public synchronized boolean uninstallPackage(String packageName) {\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        if (ps != null) {\n            uninstallPackageFully(ps);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean clearPackageAsUser(int userId, String packageName) throws RemoteException {\n        if (!VUserManagerService.get().exists(userId)) {\n            return false;\n        }\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        if (ps != null) {\n            int[] userIds = getPackageInstalledUsers(packageName);\n            if (!ArrayUtils.contains(userIds, userId)) {\n                return false;\n            }\n            if (userIds.length == 1) {\n                clearPackage(packageName);\n            } else {\n                // Just hidden it\n                VActivityManagerService.get().killAppByPkg(packageName, userId);\n                ps.setInstalled(userId, false);\n                mPersistenceLayer.save();\n                FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(userId, packageName));\n                FileUtils.deleteDir(VEnvironment.getVirtualPrivateStorageDir(userId, packageName));\n            }\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean clearPackage(String packageName) throws RemoteException {\n        try {\n            BroadcastSystem.get().stopApp(packageName);\n            VActivityManagerService.get().killAppByPkg(packageName, VUserHandle.USER_ALL);\n\n            for (int id : VUserManagerService.get().getUserIds()) {\n                FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(id, packageName));\n                FileUtils.deleteDir(VEnvironment.getVirtualPrivateStorageDir(id, packageName));\n            }\n            return true;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    @Override\n    public synchronized boolean uninstallPackageAsUser(String packageName, int userId) {\n        if (!VUserManagerService.get().exists(userId)) {\n            return false;\n        }\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        if (ps != null) {\n            int[] userIds = getPackageInstalledUsers(packageName);\n            if (!ArrayUtils.contains(userIds, userId)) {\n                return false;\n            }\n            if (userIds.length == 1) {\n                uninstallPackageFully(ps);\n            } else {\n                // Just hidden it\n                VActivityManagerService.get().killAppByPkg(packageName, userId);\n                ps.setInstalled(userId, false);\n                notifyAppUninstalled(ps, userId);\n                mPersistenceLayer.save();\n                FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(userId, packageName));\n                FileUtils.deleteDir(VEnvironment.getVirtualPrivateStorageDir(userId, packageName));\n            }\n            return true;\n        }\n        return false;\n    }\n\n    private void uninstallPackageFully(PackageSetting ps) {\n        String packageName = ps.packageName;\n        try {\n            BroadcastSystem.get().stopApp(packageName);\n            VActivityManagerService.get().killAppByPkg(packageName, VUserHandle.USER_ALL);\n            VEnvironment.getPackageResourcePath(packageName).delete();\n            FileUtils.deleteDir(VEnvironment.getDataAppPackageDirectory(packageName));\n            VEnvironment.getOdexFile(packageName).delete();\n            for (int id : VUserManagerService.get().getUserIds()) {\n                FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(id, packageName));\n                FileUtils.deleteDir(VEnvironment.getVirtualPrivateStorageDir(id, packageName));\n            }\n            PackageCacheManager.remove(packageName);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            notifyAppUninstalled(ps, -1);\n        }\n    }\n\n    @Override\n    public int[] getPackageInstalledUsers(String packageName) {\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        if (ps != null) {\n            IntArray installedUsers = new IntArray(5);\n            int[] userIds = VUserManagerService.get().getUserIds();\n            for (int userId : userIds) {\n                if (ps.readUserState(userId).installed) {\n                    installedUsers.add(userId);\n                }\n            }\n            return installedUsers.getAll();\n        }\n        return new int[0];\n    }\n\n    @Override\n    public List<InstalledAppInfo> getInstalledApps(int flags) {\n        List<InstalledAppInfo> infoList = new ArrayList<>(getInstalledAppCount());\n        for (VPackage p : PackageCacheManager.PACKAGE_CACHE.values()) {\n            PackageSetting setting = (PackageSetting) p.mExtras;\n            infoList.add(setting.getAppInfo());\n        }\n        return infoList;\n    }\n\n    @Override\n    public List<InstalledAppInfo> getInstalledAppsAsUser(int userId, int flags) {\n        List<InstalledAppInfo> infoList = new ArrayList<>(getInstalledAppCount());\n        for (VPackage p : PackageCacheManager.PACKAGE_CACHE.values()) {\n            PackageSetting setting = (PackageSetting) p.mExtras;\n            boolean visible = setting.isInstalled(userId);\n            if ((flags & VirtualCore.GET_HIDDEN_APP) == 0 && setting.isHidden(userId)) {\n                visible = false;\n            }\n            if (visible) {\n                infoList.add(setting.getAppInfo());\n            }\n        }\n        return infoList;\n    }\n\n    @Override\n    public int getInstalledAppCount() {\n        return PackageCacheManager.PACKAGE_CACHE.size();\n    }\n\n    @Override\n    public boolean isAppInstalled(String packageName) {\n        return packageName != null && PackageCacheManager.PACKAGE_CACHE.containsKey(packageName);\n    }\n\n    @Override\n    public boolean isAppInstalledAsUser(int userId, String packageName) {\n        if (packageName == null || !VUserManagerService.get().exists(userId)) {\n            return false;\n        }\n        PackageSetting setting = PackageCacheManager.getSetting(packageName);\n        if (setting == null) {\n            return false;\n        }\n        return setting.isInstalled(userId);\n    }\n\n    private void notifyAppInstalled(PackageSetting setting, int userId) {\n        final String pkg = setting.packageName;\n        int N = mRemoteCallbackList.beginBroadcast();\n        while (N-- > 0) {\n            try {\n                if (userId == -1) {\n                    sendInstalledBroadcast(pkg);\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalled(pkg);\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(0, pkg);\n\n                } else {\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(userId, pkg);\n                }\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        mRemoteCallbackList.finishBroadcast();\n        VAccountManagerService.get().refreshAuthenticatorCache(null);\n    }\n\n    private void notifyAppUninstalled(PackageSetting setting, int userId) {\n        final String pkg = setting.packageName;\n        int N = mRemoteCallbackList.beginBroadcast();\n        while (N-- > 0) {\n            try {\n                if (userId == -1) {\n                    sendUninstalledBroadcast(pkg);\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalled(pkg);\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalledAsUser(0, pkg);\n                } else {\n                    mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalledAsUser(userId, pkg);\n                }\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        mRemoteCallbackList.finishBroadcast();\n        VAccountManagerService.get().refreshAuthenticatorCache(null);\n    }\n\n\n    private void sendInstalledBroadcast(String packageName) {\n        Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);\n        intent.setData(Uri.parse(\"package:\" + packageName));\n        VActivityManagerService.get().sendBroadcastAsUser(intent, VUserHandle.ALL);\n    }\n\n    private void sendUninstalledBroadcast(String packageName) {\n        Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);\n        intent.setData(Uri.parse(\"package:\" + packageName));\n        VActivityManagerService.get().sendBroadcastAsUser(intent, VUserHandle.ALL);\n    }\n\n    @Override\n    public void registerObserver(IPackageObserver observer) {\n        try {\n            mRemoteCallbackList.register(observer);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void unregisterObserver(IPackageObserver observer) {\n        try {\n            mRemoteCallbackList.unregister(observer);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public IAppRequestListener getAppRequestListener() {\n        return mAppRequestListener;\n    }\n\n    @Override\n    public void setAppRequestListener(final IAppRequestListener listener) {\n        this.mAppRequestListener = listener;\n        if (listener != null) {\n            try {\n                listener.asBinder().linkToDeath(new DeathRecipient() {\n                    @Override\n                    public void binderDied() {\n                        listener.asBinder().unlinkToDeath(this, 0);\n                        VAppManagerService.this.mAppRequestListener = null;\n                    }\n                }, 0);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Override\n    public void clearAppRequestListener() {\n        this.mAppRequestListener = null;\n    }\n\n    @Override\n    public InstalledAppInfo getInstalledAppInfo(String packageName, int flags) {\n        synchronized (PackageCacheManager.class) {\n            if (packageName != null) {\n                PackageSetting setting = PackageCacheManager.getSetting(packageName);\n                if (setting != null) {\n                    return setting.getAppInfo();\n                }\n            }\n            return null;\n        }\n    }\n\n    public boolean isPackageLaunched(int userId, String packageName) {\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        return ps != null && ps.isLaunched(userId);\n    }\n\n    public void setPackageHidden(int userId, String packageName, boolean hidden) {\n        PackageSetting ps = PackageCacheManager.getSetting(packageName);\n        if (ps != null && VUserManagerService.get().exists(userId)) {\n            ps.setHidden(userId, hidden);\n            mPersistenceLayer.save();\n        }\n    }\n\n    public int getAppId(String packageName) {\n        PackageSetting setting = PackageCacheManager.getSetting(packageName);\n        return setting != null ? setting.appId : -1;\n    }\n\n\n    void restoreFactoryState() {\n        VLog.w(TAG, \"Warning: Restore the factory state...\");\n        VEnvironment.getDalvikCacheDirectory().delete();\n        VEnvironment.getUserSystemDirectory().delete();\n        VEnvironment.getDataAppDirectory().delete();\n    }\n\n    public void savePersistenceData() {\n        mPersistenceLayer.save();\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.annotation.TargetApi;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.fixer.ComponentFixer;\nimport com.lody.virtual.client.stub.VASettings;\nimport com.lody.virtual.helper.compat.ObjectsCompat;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.server.IPackageInstaller;\nimport com.lody.virtual.server.IPackageManager;\nimport com.lody.virtual.server.pm.installer.VPackageInstallerService;\nimport com.lody.virtual.server.pm.parser.PackageParserEx;\nimport com.lody.virtual.server.pm.parser.VPackage;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;\n\n/**\n * @author Lody\n */\npublic class VPackageManagerService extends IPackageManager.Stub {\n\n    static final String TAG = \"PackageManager\";\n    static final Comparator<ResolveInfo> sResolvePrioritySorter = new Comparator<ResolveInfo>() {\n        public int compare(ResolveInfo r1, ResolveInfo r2) {\n            int v1 = r1.priority;\n            int v2 = r2.priority;\n            if (v1 != v2) {\n                return (v1 > v2) ? -1 : 1;\n            }\n            v1 = r1.preferredOrder;\n            v2 = r2.preferredOrder;\n            if (v1 != v2) {\n                return (v1 > v2) ? -1 : 1;\n            }\n            if (r1.isDefault != r2.isDefault) {\n                return r1.isDefault ? -1 : 1;\n            }\n            v1 = r1.match;\n            v2 = r2.match;\n            if (v1 != v2) {\n                return (v1 > v2) ? -1 : 1;\n            }\n            return 0;\n        }\n    };\n    private static final AtomicReference<VPackageManagerService> gService = new AtomicReference<>();\n    private static final Comparator<ProviderInfo> sProviderInitOrderSorter = new Comparator<ProviderInfo>() {\n        public int compare(ProviderInfo p1, ProviderInfo p2) {\n            final int v1 = p1.initOrder;\n            final int v2 = p2.initOrder;\n            return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);\n        }\n    };\n\n    private final ResolveInfo mResolveInfo;\n\n    private final ActivityIntentResolver mActivities = new ActivityIntentResolver();\n    private final ServiceIntentResolver mServices = new ServiceIntentResolver();\n    private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();\n    private final ProviderIntentResolver mProviders = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? new ProviderIntentResolver() : null;\n\n    private final HashMap<ComponentName, VPackage.ProviderComponent> mProvidersByComponent = new HashMap<>();\n\n    private final HashMap<String, VPackage.PermissionComponent> mPermissions = new HashMap<>();\n    private final HashMap<String, VPackage.PermissionGroupComponent> mPermissionGroups = new HashMap<>();\n    private final HashMap<String, VPackage.ProviderComponent> mProvidersByAuthority = new HashMap<>();\n\n    private final Map<String, VPackage> mPackages = PackageCacheManager.PACKAGE_CACHE;\n\n\n    public VPackageManagerService() {\n        Intent intent = new Intent();\n        intent.setClassName(VirtualCore.get().getHostPkg(), VASettings.RESOLVER_ACTIVITY);\n        mResolveInfo = VirtualCore.get().getUnHookPackageManager().resolveActivity(intent, 0);\n    }\n\n    public static void systemReady() {\n        VPackageManagerService instance = new VPackageManagerService();\n        new VUserManagerService(VirtualCore.get().getContext(), instance, new char[0], instance.mPackages);\n        gService.set(instance);\n    }\n\n    public static VPackageManagerService get() {\n        return gService.get();\n    }\n\n\n    void analyzePackageLocked(VPackage pkg) {\n        int N = pkg.activities.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ActivityComponent a = pkg.activities.get(i);\n            if (a.info.processName == null) {\n                a.info.processName = a.info.packageName;\n            }\n            mActivities.addActivity(a, \"activity\");\n        }\n        N = pkg.services.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ServiceComponent a = pkg.services.get(i);\n            if (a.info.processName == null) {\n                a.info.processName = a.info.packageName;\n            }\n            mServices.addService(a);\n        }\n        N = pkg.receivers.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ActivityComponent a = pkg.receivers.get(i);\n            if (a.info.processName == null) {\n                a.info.processName = a.info.packageName;\n            }\n            mReceivers.addActivity(a, \"receiver\");\n        }\n\n        N = pkg.providers.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ProviderComponent p = pkg.providers.get(i);\n            if (p.info.processName == null) {\n                p.info.processName = p.info.packageName;\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n                mProviders.addProvider(p);\n            }\n            String names[] = p.info.authority.split(\";\");\n            for (String name : names) {\n                if (!mProvidersByAuthority.containsKey(name)) {\n                    mProvidersByAuthority.put(name, p);\n                }\n            }\n            mProvidersByComponent.put(p.getComponentName(), p);\n        }\n\n        N = pkg.permissions.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.PermissionComponent permission = pkg.permissions.get(i);\n            mPermissions.put(permission.className, permission);\n        }\n        N = pkg.permissionGroups.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.PermissionGroupComponent group = pkg.permissionGroups.get(i);\n            mPermissionGroups.put(group.className, group);\n        }\n    }\n\n    void deletePackageLocked(String packageName) {\n        VPackage pkg = mPackages.get(packageName);\n        if (pkg == null) {\n            return;\n        }\n        int N = pkg.activities.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ActivityComponent a = pkg.activities.get(i);\n            mActivities.removeActivity(a, \"activity\");\n        }\n        N = pkg.services.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ServiceComponent a = pkg.services.get(i);\n            mServices.removeService(a);\n        }\n        N = pkg.receivers.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ActivityComponent a = pkg.receivers.get(i);\n            mReceivers.removeActivity(a, \"receiver\");\n        }\n\n        N = pkg.providers.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.ProviderComponent p = pkg.providers.get(i);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n                mProviders.removeProvider(p);\n            }\n            String names[] = p.info.authority.split(\";\");\n            for (String name : names) {\n                mProvidersByAuthority.remove(name);\n            }\n            mProvidersByComponent.remove(p.getComponentName());\n        }\n\n        N = pkg.permissions.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.PermissionComponent permission = pkg.permissions.get(i);\n            mPermissions.remove(permission.className);\n        }\n        N = pkg.permissionGroups.size();\n        for (int i = 0; i < N; i++) {\n            VPackage.PermissionGroupComponent group = pkg.permissionGroups.get(i);\n            mPermissionGroups.remove(group.className);\n        }\n    }\n\n    @Override\n    public List<String> getSharedLibraries(String packageName) {\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(packageName);\n            if (p != null) {\n                ArrayList<String> list = new ArrayList<>();\n                if (p.usesLibraries != null) {\n                    list.addAll(p.usesLibraries);\n                }\n                if (p.usesOptionalLibraries != null) {\n                    list.addAll(p.usesOptionalLibraries);\n                }\n                return list;\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public int checkPermission(String permName, String pkgName, int userId) {\n        if (\"android.permission.INTERACT_ACROSS_USERS\".equals(permName)\n                || \"android.permission.INTERACT_ACROSS_USERS_FULL\".equals(permName)) {\n            return PackageManager.PERMISSION_DENIED;\n        }\n        return VirtualCore.get().getPackageManager().checkPermission(permName, VirtualCore.get().getHostPkg());\n    }\n\n    @Override\n    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {\n        checkUserId(userId);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(packageName);\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                return generatePackageInfo(p, ps, flags, userId);\n            }\n        }\n        return null;\n    }\n\n    private PackageInfo generatePackageInfo(VPackage p, PackageSetting ps, int flags, int userId) {\n        flags = updateFlagsNought(flags);\n        PackageInfo packageInfo = PackageParserEx.generatePackageInfo(p, flags,\n                ps.firstInstallTime, ps.lastUpdateTime, ps.readUserState(userId), userId);\n        if (packageInfo != null) {\n            Parcel parcel = Parcel.obtain();\n            packageInfo.writeToParcel(parcel, 0);\n            PackageInfo info = PackageInfo.CREATOR.createFromParcel(parcel);\n            parcel.recycle();\n            return info;\n        }\n        return null;\n    }\n\n    private int updateFlagsNought(int flags) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            return flags;\n        }\n        if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE\n                | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {\n            // Caller expressed an explicit opinion about what encryption\n            // aware/unaware components they want to see, so fall through and\n            // give them what they want\n        } else {\n            // Caller expressed no opinion, so match based on user state\n            flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;\n        }\n        return flags;\n    }\n\n    private void checkUserId(int userId) {\n        if (!VUserManagerService.get().exists(userId)) {\n            throw new SecurityException(\"Invalid userId \" + userId);\n        }\n    }\n\n    @Override\n    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(component.getPackageName());\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                VPackage.ActivityComponent a = mActivities.mActivities.get(component);\n                if (a != null) {\n                    ActivityInfo activityInfo = PackageParserEx.generateActivityInfo(a, flags, ps.readUserState(userId), userId);\n                    ComponentFixer.fixComponentInfo(ps, activityInfo, userId);\n                    return activityInfo;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) {\n        synchronized (mPackages) {\n            VPackage.ActivityComponent a = mActivities.mActivities.get(component);\n            if (a == null) {\n                return false;\n            }\n            for (int i = 0; i < a.intents.size(); i++) {\n                if (a.intents.get(i).filter.match(intent.getAction(), resolvedType, intent.getScheme(), intent.getData(),\n                        intent.getCategories(), TAG) >= 0) {\n                    return true;\n                }\n            }\n            return false;\n        }\n    }\n\n    @Override\n    public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(component.getPackageName());\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                VPackage.ActivityComponent a = mReceivers.mActivities.get(component);\n                if (a != null) {\n                    ActivityInfo receiverInfo = PackageParserEx.generateActivityInfo(a, flags, ps.readUserState(userId), userId);\n                    ComponentFixer.fixComponentInfo(ps, receiverInfo, userId);\n                    return receiverInfo;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(component.getPackageName());\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                VPackage.ServiceComponent s = mServices.mServices.get(component);\n                if (s != null) {\n                    ServiceInfo serviceInfo = PackageParserEx.generateServiceInfo(s, flags, ps.readUserState(userId), userId);\n                    ComponentFixer.fixComponentInfo(ps, serviceInfo, userId);\n                    return serviceInfo;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(component.getPackageName());\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                VPackage.ProviderComponent provider = mProvidersByComponent.get(component);\n                if (provider != null) {\n                    ProviderInfo providerInfo = PackageParserEx.generateProviderInfo(provider, flags, ps.readUserState(userId), userId);\n                    ComponentFixer.fixComponentInfo(ps, providerInfo, userId);\n                    return providerInfo;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, 0);\n        return chooseBestActivity(intent, resolvedType, flags, query);\n    }\n\n    private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query) {\n        if (query != null) {\n            final int N = query.size();\n            if (N == 1) {\n                return query.get(0);\n            } else if (N > 1) {\n                // If there is more than one activity with the same priority,\n                // then let the user decide between them.\n                ResolveInfo r0 = query.get(0);\n                ResolveInfo r1 = query.get(1);\n                // If the first activity has a higher priority, or a different\n                // default, then it is always desireable to pick it.\n                if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder\n                        || r0.isDefault != r1.isDefault) {\n                    return query.get(0);\n                }\n                // If we have saved a preference for a preferred activity for\n                // this Intent, use that.\n\n                ResolveInfo ri = findPreferredActivity(intent, resolvedType,\n                        flags, query, r0.priority);\n                //noinspection ConstantConditions\n                if (ri != null) {\n                    return ri;\n                }\n                return query.get(0);\n            }\n        }\n        return null;\n    }\n\n    private ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority) {\n        return null;\n    }\n\n    @Override\n    public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ComponentName comp = intent.getComponent();\n        if (comp == null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (intent.getSelector() != null) {\n                    intent = intent.getSelector();\n                    comp = intent.getComponent();\n                }\n            }\n        }\n        if (comp != null) {\n            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);\n            final ActivityInfo ai = getActivityInfo(comp, flags, userId);\n            if (ai != null) {\n                final ResolveInfo ri = new ResolveInfo();\n                ri.activityInfo = ai;\n                list.add(ri);\n            }\n            return list;\n        }\n\n        // reader\n        synchronized (mPackages) {\n            final String pkgName = intent.getPackage();\n            if (pkgName == null) {\n                return mActivities.queryIntent(intent, resolvedType, flags, userId);\n            }\n            final VPackage pkg = mPackages.get(pkgName);\n            if (pkg != null) {\n                return mActivities.queryIntentForPackage(intent, resolvedType, flags, pkg.activities, userId);\n            }\n            return Collections.emptyList();\n        }\n    }\n\n    @Override\n    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ComponentName comp = intent.getComponent();\n        if (comp == null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (intent.getSelector() != null) {\n                    intent = intent.getSelector();\n                    comp = intent.getComponent();\n                }\n            }\n        }\n        if (comp != null) {\n            List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);\n            ActivityInfo ai = getReceiverInfo(comp, flags, userId);\n            if (ai != null) {\n                ResolveInfo ri = new ResolveInfo();\n                ri.activityInfo = ai;\n                list.add(ri);\n            }\n            return list;\n        }\n\n        // reader\n        synchronized (mPackages) {\n            String pkgName = intent.getPackage();\n            if (pkgName == null) {\n                return mReceivers.queryIntent(intent, resolvedType, flags, userId);\n            }\n            final VPackage pkg = mPackages.get(pkgName);\n            if (pkg != null) {\n                return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, userId);\n            }\n            return Collections.emptyList();\n        }\n    }\n\n    @Override\n    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);\n        if (query != null) {\n            if (query.size() >= 1) {\n                // If there is more than one service with the same priority,\n                // just arbitrarily pick the first one.\n                return query.get(0);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ComponentName comp = intent.getComponent();\n        if (comp == null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (intent.getSelector() != null) {\n                    intent = intent.getSelector();\n                    comp = intent.getComponent();\n                }\n            }\n        }\n        if (comp != null) {\n            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);\n            final ServiceInfo si = getServiceInfo(comp, flags, userId);\n            if (si != null) {\n                final ResolveInfo ri = new ResolveInfo();\n                ri.serviceInfo = si;\n                list.add(ri);\n            }\n            return list;\n        }\n\n        // reader\n        synchronized (mPackages) {\n            String pkgName = intent.getPackage();\n            if (pkgName == null) {\n                return mServices.queryIntent(intent, resolvedType, flags, userId);\n            }\n            final VPackage pkg = mPackages.get(pkgName);\n            if (pkg != null) {\n                return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services, userId);\n            }\n            return Collections.emptyList();\n        }\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    @Override\n    public List<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ComponentName comp = intent.getComponent();\n        if (comp == null) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n                if (intent.getSelector() != null) {\n                    intent = intent.getSelector();\n                    comp = intent.getComponent();\n                }\n            }\n        }\n        if (comp != null) {\n            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);\n            final ProviderInfo pi = getProviderInfo(comp, flags, userId);\n            if (pi != null) {\n                final ResolveInfo ri = new ResolveInfo();\n                ri.providerInfo = pi;\n                list.add(ri);\n            }\n            return list;\n        }\n        // reader\n        synchronized (mPackages) {\n            String pkgName = intent.getPackage();\n            if (pkgName == null) {\n                return mProviders.queryIntent(intent, resolvedType, flags, userId);\n            }\n            final VPackage pkg = mPackages.get(pkgName);\n            if (pkg != null) {\n                return mProviders.queryIntentForPackage(intent, resolvedType, flags, pkg.providers, userId);\n            }\n            return Collections.emptyList();\n        }\n    }\n\n    @Override\n    public VParceledListSlice<ProviderInfo> queryContentProviders(String processName, int vuid, int flags) {\n        int userId = VUserHandle.getUserId(vuid);\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ArrayList<ProviderInfo> finalList = new ArrayList<>(3);\n        // reader\n        synchronized (mPackages) {\n            for (VPackage.ProviderComponent p : mProvidersByComponent.values()) {\n                PackageSetting ps = (PackageSetting) p.owner.mExtras;\n                if (processName == null || ps.appId == VUserHandle.getAppId(vuid) && p.info.processName.equals(processName)) {\n                    ProviderInfo providerInfo = PackageParserEx.generateProviderInfo(p, flags, ps.readUserState(userId), userId);\n                    finalList.add(providerInfo);\n                }\n            }\n        }\n        if (!finalList.isEmpty()) {\n            Collections.sort(finalList, sProviderInitOrderSorter);\n        }\n        return new VParceledListSlice<>(finalList);\n    }\n\n    @Override\n    public VParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {\n        checkUserId(userId);\n        ArrayList<PackageInfo> pkgList = new ArrayList<>(mPackages.size());\n        synchronized (mPackages) {\n            for (VPackage p : mPackages.values()) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                PackageInfo info = generatePackageInfo(p, ps, flags, userId);\n                if (info != null) {\n                    pkgList.add(info);\n                }\n            }\n        }\n        return new VParceledListSlice<>(pkgList);\n    }\n\n    @Override\n    public VParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        ArrayList<ApplicationInfo> list = new ArrayList<>(mPackages.size());\n        synchronized (mPackages) {\n            for (VPackage p : mPackages.values()) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                ApplicationInfo info = PackageParserEx.generateApplicationInfo(p, flags, ps.readUserState(userId), userId);\n                list.add(info);\n            }\n        }\n        return new VParceledListSlice<>(list);\n    }\n\n    @Override\n    public PermissionInfo getPermissionInfo(String name, int flags) {\n        synchronized (mPackages) {\n            VPackage.PermissionComponent p = mPermissions.get(name);\n            if (p != null) {\n                return new PermissionInfo(p.info);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {\n        synchronized (mPackages) {\n            return null;\n        }\n    }\n\n    @Override\n    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {\n        synchronized (mPackages) {\n            VPackage.PermissionGroupComponent p = mPermissionGroups.get(name);\n            if (p != null) {\n                return new PermissionGroupInfo(p.info);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {\n        synchronized (mPackages) {\n            final int N = mPermissionGroups.size();\n            ArrayList<PermissionGroupInfo> out = new ArrayList<>(N);\n            for (VPackage.PermissionGroupComponent pg : mPermissionGroups.values()) {\n                out.add(new PermissionGroupInfo(pg.info));\n            }\n            return out;\n        }\n    }\n\n    @Override\n    public ProviderInfo resolveContentProvider(String name, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            final VPackage.ProviderComponent provider = mProvidersByAuthority.get(name);\n            if (provider != null) {\n                PackageSetting ps = (PackageSetting) provider.owner.mExtras;\n                ProviderInfo providerInfo = PackageParserEx.generateProviderInfo(provider, flags, ps.readUserState(userId), userId);\n                if (providerInfo != null) {\n                    VPackage p = mPackages.get(providerInfo.packageName);\n                    PackageSetting settings = (PackageSetting) p.mExtras;\n                    ComponentFixer.fixComponentInfo(settings, providerInfo, userId);\n                    return providerInfo;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {\n        checkUserId(userId);\n        flags = updateFlagsNought(flags);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(packageName);\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                return PackageParserEx.generateApplicationInfo(p, flags, ps.readUserState(userId), userId);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public String[] getPackagesForUid(int uid) {\n        int userId = VUserHandle.getUserId(uid);\n        checkUserId(userId);\n        synchronized (this) {\n            List<String> pkgList = new ArrayList<>(2);\n            for (VPackage p : mPackages.values()) {\n                PackageSetting settings = (PackageSetting) p.mExtras;\n                if (VUserHandle.getUid(userId, settings.appId) == uid) {\n                    pkgList.add(p.packageName);\n                }\n            }\n            return pkgList.toArray(new String[pkgList.size()]);\n        }\n    }\n\n    @Override\n    public int getPackageUid(String packageName, int userId) {\n        checkUserId(userId);\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(packageName);\n            if (p != null) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                return VUserHandle.getUid(userId, ps.appId);\n            }\n            return -1;\n        }\n    }\n\n    @Override\n    public String getNameForUid(int uid) {\n        int appId = VUserHandle.getAppId(uid);\n        synchronized (mPackages) {\n            for (VPackage p : mPackages.values()) {\n                PackageSetting ps = (PackageSetting) p.mExtras;\n                if (ps.appId == appId) {\n                    return ps.packageName;\n                }\n            }\n            return null;\n        }\n    }\n\n\n    @Override\n    public List<String> querySharedPackages(String packageName) {\n        synchronized (mPackages) {\n            VPackage p = mPackages.get(packageName);\n            if (p == null || p.mSharedUserId == null) {\n                // noinspection unchecked\n                return Collections.EMPTY_LIST;\n            }\n            ArrayList<String> list = new ArrayList<>();\n            for (VPackage one : mPackages.values()) {\n                if (TextUtils.equals(one.mSharedUserId, p.mSharedUserId)) {\n                    list.add(one.packageName);\n                }\n            }\n            return list;\n        }\n    }\n\n    @Override\n    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        try {\n            return super.onTransact(code, data, reply, flags);\n        } catch (Throwable e) {\n            e.printStackTrace();\n            throw e;\n        }\n    }\n\n    @Override\n    public IPackageInstaller getPackageInstaller() {\n        return VPackageInstallerService.get();\n    }\n\n    void createNewUser(int userId, File userPath) {\n        for (VPackage p : mPackages.values()) {\n            PackageSetting setting = (PackageSetting) p.mExtras;\n            setting.modifyUserState(userId);\n        }\n    }\n\n    void cleanUpUser(int userId) {\n        for (VPackage p : mPackages.values()) {\n            PackageSetting ps = (PackageSetting) p.mExtras;\n            ps.removeUser(userId);\n        }\n    }\n\n    private final class ActivityIntentResolver extends IntentResolver<VPackage.ActivityIntentInfo, ResolveInfo> {\n        // Keys are String (activity class name), values are Activity.\n        private final HashMap<ComponentName, VPackage.ActivityComponent> mActivities = new HashMap<>();\n        private int mFlags;\n\n        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {\n            mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;\n            return super.queryIntent(intent, resolvedType, defaultOnly, userId);\n        }\n\n        List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) {\n            mFlags = flags;\n            return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);\n        }\n\n        List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags,\n                                                ArrayList<VPackage.ActivityComponent> packageActivities, int userId) {\n            if (packageActivities == null) {\n                return null;\n            }\n            mFlags = flags;\n            final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;\n            final int N = packageActivities.size();\n            ArrayList<VPackage.ActivityIntentInfo[]> listCut = new ArrayList<VPackage.ActivityIntentInfo[]>(\n                    N);\n\n            ArrayList<VPackage.ActivityIntentInfo> intentFilters;\n            for (int i = 0; i < N; ++i) {\n                intentFilters = packageActivities.get(i).intents;\n                if (intentFilters != null && intentFilters.size() > 0) {\n                    VPackage.ActivityIntentInfo[] array = new VPackage.ActivityIntentInfo[intentFilters\n                            .size()];\n                    intentFilters.toArray(array);\n                    listCut.add(array);\n                }\n            }\n            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);\n        }\n\n        public final void addActivity(VPackage.ActivityComponent a, String type) {\n            mActivities.put(a.getComponentName(), a);\n            final int NI = a.intents.size();\n            for (int j = 0; j < NI; j++) {\n                VPackage.ActivityIntentInfo intent = a.intents.get(j);\n                if (intent.filter.getPriority() > 0 && \"activity\".equals(type)) {\n                    intent.filter.setPriority(0);\n                    Log.w(TAG, \"Package \" + a.info.applicationInfo.packageName + \" has activity \" + a.className\n                            + \" with priority > 0, forcing to 0\");\n                }\n                addFilter(intent);\n            }\n        }\n\n        public final void removeActivity(VPackage.ActivityComponent a, String type) {\n            mActivities.remove(a.getComponentName());\n            final int NI = a.intents.size();\n            for (int j = 0; j < NI; j++) {\n                VPackage.ActivityIntentInfo intent = a.intents.get(j);\n                removeFilter(intent);\n            }\n        }\n\n        @Override\n        protected boolean allowFilterResult(VPackage.ActivityIntentInfo filter, List<ResolveInfo> dest) {\n            ActivityInfo filterAi = filter.activity.info;\n            for (int i = dest.size() - 1; i >= 0; i--) {\n                ActivityInfo destAi = dest.get(i).activityInfo;\n                if (ObjectsCompat.equals(destAi.name, filterAi.name) && ObjectsCompat.equals(destAi.packageName, filterAi.packageName)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @Override\n        protected VPackage.ActivityIntentInfo[] newArray(int size) {\n            return new VPackage.ActivityIntentInfo[size];\n        }\n\n        @Override\n        protected boolean isFilterStopped(VPackage.ActivityIntentInfo filter) {\n            return false;\n        }\n\n        @Override\n        protected boolean isPackageForFilter(String packageName, VPackage.ActivityIntentInfo info) {\n            return packageName.equals(info.activity.owner.packageName);\n        }\n\n        @Override\n        protected ResolveInfo newResult(VPackage.ActivityIntentInfo info, int match, int userId) {\n            final VPackage.ActivityComponent activity = info.activity;\n            PackageSetting ps = (PackageSetting) activity.owner.mExtras;\n            ActivityInfo ai = PackageParserEx.generateActivityInfo(activity, mFlags, ps.readUserState(userId), userId);\n            if (ai == null) {\n                return null;\n            }\n            final ResolveInfo res = new ResolveInfo();\n            res.activityInfo = ai;\n            if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {\n                res.filter = info.filter;\n            }\n            res.priority = info.filter.getPriority();\n            res.preferredOrder = activity.owner.mPreferredOrder;\n            res.match = match;\n            res.isDefault = info.hasDefault;\n            res.labelRes = info.labelRes;\n            res.nonLocalizedLabel = info.nonLocalizedLabel;\n            res.icon = info.icon;\n            return res;\n        }\n\n        @Override\n        protected void sortResults(List<ResolveInfo> results) {\n            Collections.sort(results, sResolvePrioritySorter);\n        }\n\n        @Override\n        protected void dumpFilter(PrintWriter out, String prefix, VPackage.ActivityIntentInfo filter) {\n\n        }\n\n        @Override\n        protected Object filterToLabel(VPackage.ActivityIntentInfo filter) {\n            return filter.activity;\n        }\n\n        protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {\n\n        }\n    }\n\n    private final class ServiceIntentResolver extends IntentResolver<VPackage.ServiceIntentInfo, ResolveInfo> {\n        // Keys are String (activity class name), values are Activity.\n        private final HashMap<ComponentName, VPackage.ServiceComponent> mServices = new HashMap<>();\n        private int mFlags;\n\n        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {\n            mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;\n            return super.queryIntent(intent, resolvedType, defaultOnly, userId);\n        }\n\n        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) {\n            mFlags = flags;\n            return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);\n        }\n\n        public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags,\n                                                       ArrayList<VPackage.ServiceComponent> packageServices, int userId) {\n            if (packageServices == null) {\n                return null;\n            }\n            mFlags = flags;\n            final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;\n            final int N = packageServices.size();\n            ArrayList<VPackage.ServiceIntentInfo[]> listCut = new ArrayList<VPackage.ServiceIntentInfo[]>(N);\n\n            ArrayList<VPackage.ServiceIntentInfo> intentFilters;\n            for (int i = 0; i < N; ++i) {\n                intentFilters = packageServices.get(i).intents;\n                if (intentFilters != null && intentFilters.size() > 0) {\n                    VPackage.ServiceIntentInfo[] array = new VPackage.ServiceIntentInfo[intentFilters.size()];\n                    intentFilters.toArray(array);\n                    listCut.add(array);\n                }\n            }\n            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);\n        }\n\n        public final void addService(VPackage.ServiceComponent s) {\n            mServices.put(s.getComponentName(), s);\n            final int NI = s.intents.size();\n            int j;\n            for (j = 0; j < NI; j++) {\n                VPackage.ServiceIntentInfo intent = s.intents.get(j);\n                addFilter(intent);\n            }\n        }\n\n        public final void removeService(VPackage.ServiceComponent s) {\n            mServices.remove(s.getComponentName());\n            final int NI = s.intents.size();\n            int j;\n            for (j = 0; j < NI; j++) {\n                VPackage.ServiceIntentInfo intent = s.intents.get(j);\n                removeFilter(intent);\n            }\n        }\n\n        @Override\n        protected boolean allowFilterResult(VPackage.ServiceIntentInfo filter, List<ResolveInfo> dest) {\n            ServiceInfo filterSi = filter.service.info;\n            for (int i = dest.size() - 1; i >= 0; i--) {\n                ServiceInfo destAi = dest.get(i).serviceInfo;\n                if (ObjectsCompat.equals(destAi.name, filterSi.name)\n                        && ObjectsCompat.equals(destAi.packageName, filterSi.packageName)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @Override\n        protected VPackage.ServiceIntentInfo[] newArray(int size) {\n            return new VPackage.ServiceIntentInfo[size];\n        }\n\n        @Override\n        protected boolean isFilterStopped(VPackage.ServiceIntentInfo filter) {\n            return false;\n        }\n\n        @Override\n        protected boolean isPackageForFilter(String packageName, VPackage.ServiceIntentInfo info) {\n            return packageName.equals(info.service.owner.packageName);\n        }\n\n        @Override\n        protected ResolveInfo newResult(VPackage.ServiceIntentInfo filter, int match, int userId) {\n            final VPackage.ServiceComponent service = filter.service;\n            PackageSetting ps = (PackageSetting) service.owner.mExtras;\n            ServiceInfo si = PackageParserEx.generateServiceInfo(service, mFlags, ps.readUserState(userId), userId);\n            if (si == null) {\n                return null;\n            }\n            final ResolveInfo res = new ResolveInfo();\n            res.serviceInfo = si;\n            if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {\n                res.filter = filter.filter;\n            }\n            res.priority = filter.filter.getPriority();\n            res.preferredOrder = service.owner.mPreferredOrder;\n            res.match = match;\n            res.isDefault = filter.hasDefault;\n            res.labelRes = filter.labelRes;\n            res.nonLocalizedLabel = filter.nonLocalizedLabel;\n            res.icon = filter.icon;\n            return res;\n        }\n\n        @Override\n        protected void sortResults(List<ResolveInfo> results) {\n            Collections.sort(results, sResolvePrioritySorter);\n        }\n\n        @Override\n        protected void dumpFilter(PrintWriter out, String prefix, VPackage.ServiceIntentInfo filter) {\n\n        }\n\n        @Override\n        protected Object filterToLabel(VPackage.ServiceIntentInfo filter) {\n            return filter.service;\n        }\n\n        protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VUserManagerService.java",
    "content": "package com.lody.virtual.server.pm;\n\nimport android.app.Activity;\nimport android.app.IStopUserCallback;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Binder;\nimport android.util.SparseArray;\nimport android.util.Xml;\n\nimport com.lody.virtual.R;\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.helper.compat.ActivityManagerCompat;\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.AtomicFile;\nimport com.lody.virtual.helper.utils.FastXmlSerializer;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VBinder;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.os.VUserInfo;\nimport com.lody.virtual.os.VUserManager;\nimport com.lody.virtual.server.am.VActivityManagerService;\nimport com.lody.virtual.server.IUserManager;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\n\n\n/**\n * @author Lody\n */\npublic class VUserManagerService extends IUserManager.Stub {\n\n    private static final String LOG_TAG = \"VUserManagerService\";\n\n    private static final boolean DBG = false;\n\n    private static final String TAG_NAME = \"name\";\n    private static final String ATTR_FLAGS = \"flags\";\n    private static final String ATTR_ICON_PATH = \"icon\";\n    private static final String ATTR_ID = \"id\";\n    private static final String ATTR_CREATION_TIME = \"created\";\n    private static final String ATTR_LAST_LOGGED_IN_TIME = \"lastLoggedIn\";\n    private static final String ATTR_SERIAL_NO = \"serialNumber\";\n    private static final String ATTR_NEXT_SERIAL_NO = \"nextSerialNumber\";\n    private static final String ATTR_PARTIAL = \"partial\";\n    private static final String ATTR_USER_VERSION = \"version\";\n    private static final String TAG_USERS = \"users\";\n    private static final String TAG_USER = \"user\";\n\n    private static final String USER_INFO_DIR = \"system\" + File.separator + \"users\";\n    private static final String USER_LIST_FILENAME = \"userlist.xml\";\n    private static final String USER_PHOTO_FILENAME = \"photo.png\";\n\n    private static final int MIN_USER_ID = 1;\n\n    private static final int USER_VERSION = 1;\n\n    private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms\n    private static VUserManagerService sInstance;\n    private final Context mContext;\n    private final VPackageManagerService mPm;\n    private final Object mInstallLock;\n    private final Object mPackagesLock;\n    private final File mUsersDir;\n    private final File mUserListFile;\n    private final File mBaseUserPath;\n    private SparseArray<VUserInfo> mUsers = new SparseArray<VUserInfo>();\n    private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();\n    private int[] mUserIds;\n    private boolean mGuestEnabled;\n    private int mNextSerialNumber;\n    // This resets on a reboot. Otherwise it keeps incrementing so that user ids are\n    // not reused in quick succession\n    private int mNextUserId = MIN_USER_ID;\n    private int mUserVersion = 0;\n\n    /**\n     * Called by package manager to create the service.  This is closely\n     * associated with the package manager, and the given lock is the\n     * package manager's own lock.\n     */\n    VUserManagerService(Context context, VPackageManagerService pm,\n                        Object installLock, Object packagesLock) {\n        this(context, pm, installLock, packagesLock,\n                VEnvironment.getDataDirectory(),\n                new File(VEnvironment.getDataDirectory(), \"user\"));\n    }\n\n    /**\n     * Available for testing purposes.\n     */\n    private VUserManagerService(Context context, VPackageManagerService pm,\n                                Object installLock, Object packagesLock,\n                                File dataDir, File baseUserPath) {\n        mContext = context;\n        mPm = pm;\n        mInstallLock = installLock;\n        mPackagesLock = packagesLock;\n        synchronized (mInstallLock) {\n            synchronized (mPackagesLock) {\n                mUsersDir = new File(dataDir, USER_INFO_DIR);\n                mUsersDir.mkdirs();\n                // Make zeroth user directory, for services to migrate their files to that location\n                File userZeroDir = new File(mUsersDir, \"0\");\n                userZeroDir.mkdirs();\n                mBaseUserPath = baseUserPath;\n//                FileUtils.setPermissions(mUsersDir.toString(),\n//                        FileUtils.S_IRWXU|FileUtils.S_IRWXG\n//                        |FileUtils.S_IROTH|FileUtils.S_IXOTH,\n//                        -1, -1);\n                mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);\n                readUserListLocked();\n                // Prune out any partially created/partially removed users.\n                ArrayList<VUserInfo> partials = new ArrayList<VUserInfo>();\n                for (int i = 0; i < mUsers.size(); i++) {\n                    VUserInfo ui = mUsers.valueAt(i);\n                    if (ui.partial && i != 0) {\n                        partials.add(ui);\n                    }\n                }\n                for (int i = 0; i < partials.size(); i++) {\n                    VUserInfo ui = partials.get(i);\n                    VLog.w(LOG_TAG, \"Removing partially created user #\" + i\n                            + \" (name=\" + ui.name + \")\");\n                    removeUserStateLocked(ui.id);\n                }\n                sInstance = this;\n            }\n        }\n    }\n\n    public static VUserManagerService get() {\n        synchronized (VUserManagerService.class) {\n            return sInstance;\n        }\n    }\n\n    /**\n     * Enforces that only the system UID or root's UID or apps that have the\n     * {android.Manifest.permission.MANAGE_USERS MANAGE_USERS}\n     * permission can make certain calls to the VUserManager.\n     *\n     * @param message used as message if SecurityException is thrown\n     * @throws SecurityException if the caller is not system or root\n     */\n    private static void checkManageUsersPermission(String message) {\n        final int uid = VBinder.getCallingUid();\n        if (uid != VirtualCore.get().myUid()) {\n            throw new SecurityException(\"You need MANAGE_USERS permission to: \" + message);\n        }\n    }\n\n    @Override\n    public List<VUserInfo> getUsers(boolean excludeDying) {\n        //checkManageUsersPermission(\"query users\");\n        synchronized (mPackagesLock) {\n            ArrayList<VUserInfo> users = new ArrayList<VUserInfo>(mUsers.size());\n            for (int i = 0; i < mUsers.size(); i++) {\n                VUserInfo ui = mUsers.valueAt(i);\n                if (ui.partial) {\n                    continue;\n                }\n                if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {\n                    users.add(ui);\n                }\n            }\n            return users;\n        }\n    }\n\n    @Override\n    public VUserInfo getUserInfo(int userId) {\n        //checkManageUsersPermission(\"query user\");\n        synchronized (mPackagesLock) {\n            return getUserInfoLocked(userId);\n        }\n    }\n\n    /*\n     * Should be locked on mUsers before calling this.\n     */\n    private VUserInfo getUserInfoLocked(int userId) {\n        VUserInfo ui = mUsers.get(userId);\n        // If it is partial and not in the process of being removed, return as unknown user.\n        if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {\n            VLog.w(LOG_TAG, \"getUserInfo: unknown user #\" + userId);\n            return null;\n        }\n        return ui;\n    }\n\n    public boolean exists(int userId) {\n        synchronized (mPackagesLock) {\n            return ArrayUtils.contains(mUserIds, userId);\n        }\n    }\n\n    @Override\n    public void setUserName(int userId, String name) {\n        checkManageUsersPermission(\"rename users\");\n        boolean changed = false;\n        synchronized (mPackagesLock) {\n            VUserInfo info = mUsers.get(userId);\n            if (info == null || info.partial) {\n                VLog.w(LOG_TAG, \"setUserName: unknown user #\" + userId);\n                return;\n            }\n            if (name != null && !name.equals(info.name)) {\n                info.name = name;\n                writeUserLocked(info);\n                changed = true;\n            }\n        }\n        if (changed) {\n            sendUserInfoChangedBroadcast(userId);\n        }\n    }\n\n    @Override\n    public void setUserIcon(int userId, Bitmap bitmap) {\n        checkManageUsersPermission(\"update users\");\n        synchronized (mPackagesLock) {\n            VUserInfo info = mUsers.get(userId);\n            if (info == null || info.partial) {\n                VLog.w(LOG_TAG, \"setUserIcon: unknown user #\" + userId);\n                return;\n            }\n            writeBitmapLocked(info, bitmap);\n            writeUserLocked(info);\n        }\n        sendUserInfoChangedBroadcast(userId);\n    }\n\n    private void sendUserInfoChangedBroadcast(int userId) {\n        Intent changedIntent = new Intent(Constants.ACTION_USER_INFO_CHANGED);\n        changedIntent.putExtra(Constants.EXTRA_USER_HANDLE, userId);\n        changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);\n        VActivityManagerService.get().sendBroadcastAsUser(changedIntent, new VUserHandle(userId));\n    }\n\n    @Override\n    public Bitmap getUserIcon(int userId) {\n        //checkManageUsersPermission(\"read users\");\n        synchronized (mPackagesLock) {\n            VUserInfo info = mUsers.get(userId);\n            if (info == null || info.partial) {\n                VLog.w(LOG_TAG, \"getUserIcon: unknown user #\" + userId);\n                return null;\n            }\n            if (info.iconPath == null) {\n                return null;\n            }\n            return BitmapFactory.decodeFile(info.iconPath);\n        }\n    }\n\n    @Override\n    public boolean isGuestEnabled() {\n        synchronized (mPackagesLock) {\n            return mGuestEnabled;\n        }\n    }\n\n    @Override\n    public void setGuestEnabled(boolean enable) {\n        checkManageUsersPermission(\"enable guest users\");\n        synchronized (mPackagesLock) {\n            if (mGuestEnabled != enable) {\n                mGuestEnabled = enable;\n                // Erase any guest user that currently exists\n                for (int i = 0; i < mUsers.size(); i++) {\n                    VUserInfo user = mUsers.valueAt(i);\n                    if (!user.partial && user.isGuest()) {\n                        if (!enable) {\n                            removeUser(user.id);\n                        }\n                        return;\n                    }\n                }\n                // No guest was found\n                if (enable) {\n                    createUser(\"Guest\", VUserInfo.FLAG_GUEST);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void wipeUser(int userHandle) {\n        checkManageUsersPermission(\"wipe user\");\n        // TODO:\n    }\n\n    public void makeInitialized(int userId) {\n        checkManageUsersPermission(\"makeInitialized\");\n        synchronized (mPackagesLock) {\n            VUserInfo info = mUsers.get(userId);\n            if (info == null || info.partial) {\n                VLog.w(LOG_TAG, \"makeInitialized: unknown user #\" + userId);\n            }\n            if ((info.flags& VUserInfo.FLAG_INITIALIZED) == 0) {\n                info.flags |= VUserInfo.FLAG_INITIALIZED;\n                writeUserLocked(info);\n            }\n        }\n    }\n\n    /**\n     * Check if we've hit the limit of how many users can be created.\n     */\n    private boolean isUserLimitReachedLocked() {\n        int nUsers = mUsers.size();\n        return nUsers >= VUserManager.getMaxSupportedUsers();\n    }\n\n    private void writeBitmapLocked(VUserInfo info, Bitmap bitmap) {\n        try {\n            File dir = new File(mUsersDir, Integer.toString(info.id));\n            File file = new File(dir, USER_PHOTO_FILENAME);\n            if (!dir.exists()) {\n                dir.mkdir();\n//                FileUtils.setPermissions(\n//                        dir.getPath(),\n//                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,\n//                        -1, -1);\n            }\n            FileOutputStream os;\n            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {\n                info.iconPath = file.getAbsolutePath();\n            }\n            try {\n                os.close();\n            } catch (IOException ioe) {\n                // What the ... !\n            }\n        } catch (FileNotFoundException e) {\n            VLog.w(LOG_TAG, \"Error setting photo for user \", e);\n        }\n    }\n\n    /**\n     * Returns an array of user ids. This array is cached here for quick access, so do not modify or\n     * cache it elsewhere.\n     * @return the array of user ids.\n     */\n    public int[] getUserIds() {\n        synchronized (mPackagesLock) {\n            return mUserIds;\n        }\n    }\n\n    int[] getUserIdsLPr() {\n        return mUserIds;\n    }\n\n    private void readUserList() {\n        synchronized (mPackagesLock) {\n            readUserListLocked();\n        }\n    }\n\n    private void readUserListLocked() {\n        mGuestEnabled = false;\n        if (!mUserListFile.exists()) {\n            fallbackToSingleUserLocked();\n            return;\n        }\n        FileInputStream fis = null;\n        AtomicFile userListFile = new AtomicFile(mUserListFile);\n        try {\n            fis = userListFile.openRead();\n            XmlPullParser parser = Xml.newPullParser();\n            parser.setInput(fis, null);\n            int type;\n            while ((type = parser.next()) != XmlPullParser.START_TAG\n                    && type != XmlPullParser.END_DOCUMENT) {\n                ;\n            }\n\n            if (type != XmlPullParser.START_TAG) {\n                VLog.e(LOG_TAG, \"Unable to read user list\");\n                fallbackToSingleUserLocked();\n                return;\n            }\n\n            mNextSerialNumber = -1;\n            if (parser.getName().equals(TAG_USERS)) {\n                String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO);\n                if (lastSerialNumber != null) {\n                    mNextSerialNumber = Integer.parseInt(lastSerialNumber);\n                }\n                String versionNumber = parser.getAttributeValue(null, ATTR_USER_VERSION);\n                if (versionNumber != null) {\n                    mUserVersion = Integer.parseInt(versionNumber);\n                }\n            }\n\n            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {\n                if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {\n                    String id = parser.getAttributeValue(null, ATTR_ID);\n                    VUserInfo user = readUser(Integer.parseInt(id));\n\n                    if (user != null) {\n                        mUsers.put(user.id, user);\n                        if (user.isGuest()) {\n                            mGuestEnabled = true;\n                        }\n                        if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {\n                            mNextSerialNumber = user.id + 1;\n                        }\n                    }\n                }\n            }\n            updateUserIdsLocked();\n            upgradeIfNecessary();\n        } catch (IOException ioe) {\n            fallbackToSingleUserLocked();\n        } catch (XmlPullParserException pe) {\n            fallbackToSingleUserLocked();\n        } finally {\n            if (fis != null) {\n                try {\n                    fis.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n    /**\n     * This fixes an incorrect initialization of user name for the owner.\n     * TODO: Remove in the next release.\n     */\n    private void upgradeIfNecessary() {\n        int userVersion = mUserVersion;\n        if (userVersion < 1) {\n            // Assign a proper name for the owner, if not initialized correctly before\n            VUserInfo user = mUsers.get(VUserHandle.USER_OWNER);\n            if (\"Primary\".equals(user.name)) {\n                user.name = \"Admin\";\n                writeUserLocked(user);\n            }\n            userVersion = 1;\n        }\n\n        if (userVersion < USER_VERSION) {\n            VLog.w(LOG_TAG, \"User version \" + mUserVersion + \" didn't upgrade as expected to \"\n                    + USER_VERSION);\n        } else {\n            mUserVersion = userVersion;\n            writeUserListLocked();\n        }\n    }\n\n    private void fallbackToSingleUserLocked() {\n        // Create the primary user\n        VUserInfo primary = new VUserInfo(0,\n                mContext.getResources().getString(R.string.owner_name), null,\n                VUserInfo.FLAG_ADMIN | VUserInfo.FLAG_PRIMARY | VUserInfo.FLAG_INITIALIZED);\n        mUsers.put(0, primary);\n        mNextSerialNumber = MIN_USER_ID;\n        updateUserIdsLocked();\n\n        writeUserListLocked();\n        writeUserLocked(primary);\n    }\n\n    /*\n     * Writes the user file in this format:\n     *\n     * <user flags=\"20039023\" id=\"0\">\n     *   <name>Primary</name>\n     * </user>\n     */\n    private void writeUserLocked(VUserInfo userInfo) {\n        FileOutputStream fos = null;\n        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + \".xml\"));\n        try {\n            fos = userFile.startWrite();\n            final BufferedOutputStream bos = new BufferedOutputStream(fos);\n\n            // XmlSerializer serializer = XmlUtils.serializerInstance();\n            final XmlSerializer serializer = new FastXmlSerializer();\n            serializer.setOutput(bos, \"utf-8\");\n            serializer.startDocument(null, true);\n            serializer.setFeature(\"http://xmlpull.org/v1/doc/features.html#indent-output\", true);\n\n            serializer.startTag(null, TAG_USER);\n            serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));\n            serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));\n            serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));\n            serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));\n            serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,\n                    Long.toString(userInfo.lastLoggedInTime));\n            if (userInfo.iconPath != null) {\n                serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);\n            }\n            if (userInfo.partial) {\n                serializer.attribute(null, ATTR_PARTIAL, \"true\");\n            }\n\n            serializer.startTag(null, TAG_NAME);\n            serializer.text(userInfo.name);\n            serializer.endTag(null, TAG_NAME);\n\n            serializer.endTag(null, TAG_USER);\n\n            serializer.endDocument();\n            userFile.finishWrite(fos);\n        } catch (Exception ioe) {\n            VLog.e(LOG_TAG, \"Error writing user info \" + userInfo.id + \"\\n\" + ioe);\n            userFile.failWrite(fos);\n        }\n    }\n\n    /*\n     * Writes the user list file in this format:\n     *\n     * <users nextSerialNumber=\"3\">\n     *   <user id=\"0\"></user>\n     *   <user id=\"2\"></user>\n     * </users>\n     */\n    private void writeUserListLocked() {\n        FileOutputStream fos = null;\n        AtomicFile userListFile = new AtomicFile(mUserListFile);\n        try {\n            fos = userListFile.startWrite();\n            final BufferedOutputStream bos = new BufferedOutputStream(fos);\n\n            // XmlSerializer serializer = XmlUtils.serializerInstance();\n            final XmlSerializer serializer = new FastXmlSerializer();\n            serializer.setOutput(bos, \"utf-8\");\n            serializer.startDocument(null, true);\n            serializer.setFeature(\"http://xmlpull.org/v1/doc/features.html#indent-output\", true);\n\n            serializer.startTag(null, TAG_USERS);\n            serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));\n            serializer.attribute(null, ATTR_USER_VERSION, Integer.toString(mUserVersion));\n\n            for (int i = 0; i < mUsers.size(); i++) {\n                VUserInfo user = mUsers.valueAt(i);\n                serializer.startTag(null, TAG_USER);\n                serializer.attribute(null, ATTR_ID, Integer.toString(user.id));\n                serializer.endTag(null, TAG_USER);\n            }\n\n            serializer.endTag(null, TAG_USERS);\n\n            serializer.endDocument();\n            userListFile.finishWrite(fos);\n        } catch (Exception e) {\n            userListFile.failWrite(fos);\n            VLog.e(LOG_TAG, \"Error writing user list\");\n        }\n    }\n\n    private VUserInfo readUser(int id) {\n        int flags = 0;\n        int serialNumber = id;\n        String name = null;\n        String iconPath = null;\n        long creationTime = 0L;\n        long lastLoggedInTime = 0L;\n        boolean partial = false;\n\n        FileInputStream fis = null;\n        try {\n            AtomicFile userFile =\n                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + \".xml\"));\n            fis = userFile.openRead();\n            XmlPullParser parser = Xml.newPullParser();\n            parser.setInput(fis, null);\n            int type;\n            while ((type = parser.next()) != XmlPullParser.START_TAG\n                    && type != XmlPullParser.END_DOCUMENT) {\n                ;\n            }\n\n            if (type != XmlPullParser.START_TAG) {\n                VLog.e(LOG_TAG, \"Unable to read user \" + id);\n                return null;\n            }\n\n            if (parser.getName().equals(TAG_USER)) {\n                int storedId = readIntAttribute(parser, ATTR_ID, -1);\n                if (storedId != id) {\n                    VLog.e(LOG_TAG, \"User id does not match the file name\");\n                    return null;\n                }\n                serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);\n                flags = readIntAttribute(parser, ATTR_FLAGS, 0);\n                iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);\n                creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);\n                lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);\n                String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);\n                if (\"true\".equals(valueString)) {\n                    partial = true;\n                }\n\n                while ((type = parser.next()) != XmlPullParser.START_TAG\n                        && type != XmlPullParser.END_DOCUMENT) {\n                }\n                if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {\n                    type = parser.next();\n                    if (type == XmlPullParser.TEXT) {\n                        name = parser.getText();\n                    }\n                }\n            }\n\n            VUserInfo userInfo = new VUserInfo(id, name, iconPath, flags);\n            userInfo.serialNumber = serialNumber;\n            userInfo.creationTime = creationTime;\n            userInfo.lastLoggedInTime = lastLoggedInTime;\n            userInfo.partial = partial;\n            return userInfo;\n\n        } catch (IOException ioe) {\n        } catch (XmlPullParserException pe) {\n        } finally {\n            if (fis != null) {\n                try {\n                    fis.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n        return null;\n    }\n\n    private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {\n        String valueString = parser.getAttributeValue(null, attr);\n        if (valueString == null) return defaultValue;\n        try {\n            return Integer.parseInt(valueString);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    private long readLongAttribute(XmlPullParser parser, String attr, long defaultValue) {\n        String valueString = parser.getAttributeValue(null, attr);\n        if (valueString == null) return defaultValue;\n        try {\n            return Long.parseLong(valueString);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    @Override\n    public VUserInfo createUser(String name, int flags) {\n        checkManageUsersPermission(\"Only the system can create users\");\n\n        final long ident = Binder.clearCallingIdentity();\n        final VUserInfo userInfo;\n        try {\n            synchronized (mInstallLock) {\n                synchronized (mPackagesLock) {\n                    if (isUserLimitReachedLocked()) return null;\n                    int userId = getNextAvailableIdLocked();\n                    userInfo = new VUserInfo(userId, name, null, flags);\n                    File userPath = new File(mBaseUserPath, Integer.toString(userId));\n                    userInfo.serialNumber = mNextSerialNumber++;\n                    long now = System.currentTimeMillis();\n                    userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;\n                    userInfo.partial = true;\n                    VEnvironment.getUserSystemDirectory(userInfo.id).mkdirs();\n                    mUsers.put(userId, userInfo);\n                    writeUserListLocked();\n                    writeUserLocked(userInfo);\n                    mPm.createNewUser(userId, userPath);\n                    userInfo.partial = false;\n                    writeUserLocked(userInfo);\n                    updateUserIdsLocked();\n                }\n            }\n            Intent addedIntent = new Intent(Constants.ACTION_USER_ADDED);\n            addedIntent.putExtra(Constants.EXTRA_USER_HANDLE, userInfo.id);\n            VActivityManagerService.get().sendBroadcastAsUser(addedIntent, VUserHandle.ALL,\n                        null);\n        } finally {\n            Binder.restoreCallingIdentity(ident);\n        }\n        return userInfo;\n    }\n\n    /**\n     * Removes a user and all data directories created for that user. This method should be called\n     * after the user's processes have been terminated.\n     * @param userHandle the user's id\n     */\n    public boolean removeUser(int userHandle) {\n        checkManageUsersPermission(\"Only the system can remove users\");\n        final VUserInfo user;\n        synchronized (mPackagesLock) {\n            user = mUsers.get(userHandle);\n            if (userHandle == 0 || user == null) {\n                return false;\n            }\n            mRemovingUserIds.add(userHandle);\n            // Set this to a partially created user, so that the user will be purged\n            // on next startup, in case the runtime stops now before stopping and\n            // removing the user completely.\n            user.partial = true;\n            writeUserLocked(user);\n        }\n        if (DBG) VLog.i(LOG_TAG, \"Stopping user \" + userHandle);\n        int res = VActivityManagerService.get().stopUser(userHandle,\n                    new IStopUserCallback.Stub() {\n                        @Override\n                        public void userStopped(int userId) {\n                            finishRemoveUser(userId);\n                        }\n                        @Override\n                        public void userStopAborted(int userId) {\n                        }\n            });\n        return res == ActivityManagerCompat.USER_OP_SUCCESS;\n    }\n\n    void finishRemoveUser(final int userHandle) {\n        if (DBG) VLog.i(LOG_TAG, \"finishRemoveUser \" + userHandle);\n        // Let other services shutdown any activity and clean up their state before completely\n        // wiping the user's system directory and removing from the user list\n        long identity = Binder.clearCallingIdentity();\n        try {\n            Intent addedIntent = new Intent(Constants.ACTION_USER_REMOVED);\n            addedIntent.putExtra(Constants.EXTRA_USER_HANDLE, userHandle);\n            VActivityManagerService.get().sendOrderedBroadcastAsUser(addedIntent, VUserHandle.ALL,\n                   null,\n                    new BroadcastReceiver() {\n                        @Override\n                        public void onReceive(Context context, Intent intent) {\n                            if (DBG) {\n                                VLog.i(LOG_TAG,\n                                        \"USER_REMOVED broadcast sent, cleaning up user data \"\n                                        + userHandle);\n                            }\n                            new Thread() {\n                                public void run() {\n                                    synchronized (mInstallLock) {\n                                        synchronized (mPackagesLock) {\n                                            removeUserStateLocked(userHandle);\n                                        }\n                                    }\n                                }\n                            }.start();\n                        }\n                    },\n                    null, Activity.RESULT_OK, null, null);\n        } finally {\n            Binder.restoreCallingIdentity(identity);\n        }\n    }\n\n    private void removeUserStateLocked(int userHandle) {\n        // Cleanup package manager settings\n        mPm.cleanUpUser(userHandle);\n\n        // Remove this user from the list\n        mUsers.remove(userHandle);\n        mRemovingUserIds.remove(userHandle);\n        // Remove user file\n        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + \".xml\"));\n        userFile.delete();\n        // Update the user list\n        writeUserListLocked();\n        updateUserIdsLocked();\n        removeDirectoryRecursive(VEnvironment.getUserSystemDirectory(userHandle));\n    }\n\n    private void removeDirectoryRecursive(File parent) {\n        if (parent.isDirectory()) {\n            String[] files = parent.list();\n            for (String filename : files) {\n                File child = new File(parent, filename);\n                removeDirectoryRecursive(child);\n            }\n        }\n        parent.delete();\n    }\n\n    @Override\n    public int getUserSerialNumber(int userHandle) {\n        synchronized (mPackagesLock) {\n            if (!exists(userHandle)) return -1;\n            return getUserInfoLocked(userHandle).serialNumber;\n        }\n    }\n\n    @Override\n    public int getUserHandle(int userSerialNumber) {\n        synchronized (mPackagesLock) {\n            for (int userId : mUserIds) {\n                if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;\n            }\n            // Not found\n            return -1;\n        }\n    }\n\n    /**\n     * Caches the list of user ids in an array, adjusting the array size when necessary.\n     */\n    private void updateUserIdsLocked() {\n        int num = 0;\n        for (int i = 0; i < mUsers.size(); i++) {\n            if (!mUsers.valueAt(i).partial) {\n                num++;\n            }\n        }\n        final int[] newUsers = new int[num];\n        int n = 0;\n        for (int i = 0; i < mUsers.size(); i++) {\n            if (!mUsers.valueAt(i).partial) {\n                newUsers[n++] = mUsers.keyAt(i);\n            }\n        }\n        mUserIds = newUsers;\n    }\n\n    /**\n     * Make a note of the last started time of a user.\n     * @param userId the user that was just foregrounded\n     */\n    public void userForeground(int userId) {\n        synchronized (mPackagesLock) {\n            VUserInfo user = mUsers.get(userId);\n            long now = System.currentTimeMillis();\n            if (user == null || user.partial) {\n                VLog.w(LOG_TAG, \"userForeground: unknown user #\" + userId);\n                return;\n            }\n            if (now > EPOCH_PLUS_30_YEARS) {\n                user.lastLoggedInTime = now;\n                writeUserLocked(user);\n            }\n        }\n    }\n\n    /**\n     * Returns the next available user id, filling in any holes in the ids.\n     * TODO: May not be a good idea to recycle ids, in case it results in confusion\n     * for data and battery stats collection, or unexpected cross-talk.\n     * @return\n     */\n    private int getNextAvailableIdLocked() {\n        synchronized (mPackagesLock) {\n            int i = mNextUserId;\n            while (i < Integer.MAX_VALUE) {\n                if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {\n                    break;\n                }\n                i++;\n            }\n            mNextUserId = i + 1;\n            return i;\n        }\n    }\n\n    @Override\n    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/FileBridge.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.system.OsConstants;\nimport android.util.Log;\n\nimport com.lody.virtual.helper.utils.ArrayUtils;\nimport com.lody.virtual.helper.utils.FileUtils;\n\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.nio.ByteOrder;\n\nimport static android.system.OsConstants.AF_UNIX;\nimport static android.system.OsConstants.SOCK_STREAM;\n\n/**\n * Simple bridge that allows file access across process boundaries without\n * returning the underlying {@link FileDescriptor}. This is useful when the\n * server side needs to strongly assert that a client side is completely\n * hands-off.\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class FileBridge extends Thread {\n    private static final String TAG = \"FileBridge\";\n\n    // TODO: consider extending to support bidirectional IO\n\n    private static final int MSG_LENGTH = 8;\n\n    /**\n     * CMD_WRITE [len] [data]\n     */\n    private static final int CMD_WRITE = 1;\n    /**\n     * CMD_FSYNC\n     */\n    private static final int CMD_FSYNC = 2;\n    /**\n     * CMD_CLOSE\n     */\n    private static final int CMD_CLOSE = 3;\n\n    private FileDescriptor mTarget;\n\n    private final FileDescriptor mServer = new FileDescriptor();\n    private final FileDescriptor mClient = new FileDescriptor();\n\n    private volatile boolean mClosed;\n\n\n    public FileBridge() {\n        try {\n            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient);\n        } catch (ErrnoException e) {\n            throw new RuntimeException(\"Failed to create bridge\");\n        }\n    }\n\n    public boolean isClosed() {\n        return mClosed;\n    }\n\n    public void forceClose() {\n        closeQuietly(mTarget);\n        closeQuietly(mServer);\n        closeQuietly(mClient);\n        mClosed = true;\n    }\n\n    public void setTargetFile(FileDescriptor target) {\n        mTarget = target;\n    }\n\n    public FileDescriptor getClientSocket() {\n        return mClient;\n    }\n\n    @Override\n    public void run() {\n        final byte[] temp = new byte[8192];\n        try {\n            while (read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {\n                final int cmd = FileUtils.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);\n                if (cmd == CMD_WRITE) {\n                    // Shuttle data into local file\n                    int len = FileUtils.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);\n                    while (len > 0) {\n                        int n = read(mServer, temp, 0, Math.min(temp.length, len));\n                        if (n == -1) {\n                            throw new IOException(\n                                    \"Unexpected EOF; still expected \" + len + \" bytes\");\n                        }\n                        write(mTarget, temp, 0, n);\n                        len -= n;\n                    }\n\n                } else if (cmd == CMD_FSYNC) {\n                    // Sync and echo back to confirm\n                    Os.fsync(mTarget);\n                    write(mServer, temp, 0, MSG_LENGTH);\n\n                } else if (cmd == CMD_CLOSE) {\n                    // Close and echo back to confirm\n                    Os.fsync(mTarget);\n                    Os.close(mTarget);\n                    mClosed = true;\n                    write(mServer, temp, 0, MSG_LENGTH);\n                    break;\n                }\n            }\n\n        } catch (ErrnoException | IOException e) {\n            Log.wtf(TAG, \"Failed during bridge\", e);\n        } finally {\n            forceClose();\n        }\n    }\n\n\n    public static void closeQuietly(FileDescriptor fd) {\n\n        if (fd != null && fd.valid()) {\n            try {\n                Os.close(fd);\n            } catch (ErrnoException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional\n     * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).\n     */\n    public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {\n        ArrayUtils.checkOffsetAndCount(bytes.length, byteOffset, byteCount);\n        if (byteCount == 0) {\n            return 0;\n        }\n        try {\n            int readCount = Os.read(fd, bytes, byteOffset, byteCount);\n            if (readCount == 0) {\n                return -1;\n            }\n            return readCount;\n        } catch (ErrnoException errnoException) {\n            if (errnoException.errno == OsConstants.EAGAIN) {\n                // We return 0 rather than throw if we try to read from an empty non-blocking pipe.\n                return 0;\n            }\n            throw new IOException(errnoException);\n        }\n    }\n\n    /**\n     * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike\n     * Unix it never just writes as many bytes as happens to be convenient.)\n     */\n    public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {\n        ArrayUtils.checkOffsetAndCount(bytes.length, byteOffset, byteCount);\n        if (byteCount == 0) {\n            return;\n        }\n        try {\n            while (byteCount > 0) {\n                int bytesWritten = Os.write(fd, bytes, byteOffset, byteCount);\n                byteCount -= bytesWritten;\n                byteOffset += bytesWritten;\n            }\n        } catch (ErrnoException errnoException) {\n            throw new IOException(errnoException);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageHelper.java",
    "content": "/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lody.virtual.server.pm.installer;\n\nimport android.annotation.TargetApi;\nimport android.content.pm.PackageInstaller;\nimport android.os.Build;\n\n/**\n * Constants used internally between the PackageManager\n * and media container service transports.\n * Some utility methods to invoke MountService api.\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class PackageHelper {\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver on success.\n     *\n     * @hide\n     */\n    public static final int INSTALL_SUCCEEDED = 1;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the package is already installed.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the package archive file is invalid.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_INVALID_APK = -2;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the URI passed in is invalid.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_INVALID_URI = -3;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the package manager service found that\n     * the device didn't have enough storage space to install the app.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if a package is already installed with\n     * the same name.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the requested shared user does not\n     * exist.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_NO_SHARED_USER = -6;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if a previously installed package of the\n     * same name has a different signature than the new package (and the old\n     * package's data was not removed).\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package is requested a shared\n     * user which is already installed on the device and does not have matching\n     * signature.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package uses a shared library\n     * that is not available.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package uses a shared library\n     * that is not available.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package failed while\n     * optimizing and validating its dex files, either because there was not\n     * enough storage or the validation failed.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_DEXOPT = -11;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package failed because the\n     * current SDK version is older than that required by the package.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_OLDER_SDK = -12;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package failed because it\n     * contains a content provider with the same authority as a provider already\n     * installed in the system.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package failed because the\n     * current SDK version is newer than that required by the package.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_NEWER_SDK = -14;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package failed because it has\n     * specified that it is a test-only package and the caller has not supplied\n     * the NSTALL_ALLOW_TEST flag.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_TEST_ONLY = -15;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the package being installed contains\n     * native code, but none that is compatible with the device's CPU_ABI.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package uses a feature that is\n     * not available.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_MISSING_FEATURE = -17;\n\n    // ------ Errors related to sdcard\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if a secure container mount point\n     * couldn't be accessed on external media.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package couldn't be installed\n     * in the specified install location.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package couldn't be installed\n     * in the specified install location because the media is not available.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package couldn't be installed\n     * because the verification timed out.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package couldn't be installed\n     * because the verification did not succeed.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the package changed from what the\n     * calling program expected.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package is assigned a\n     * different UID than it previously held.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_UID_CHANGED = -24;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the new package has an older version\n     * code than the currently installed package.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;\n\n    /**\n     * Installation return code: this is passed to the\n     * IPackageInstallObserver if the old package has target SDK high\n     * enough to support runtime permission and the new package has target SDK\n     * low enough to not support runtime permissions.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser was given a path that is\n     * not a file, or does not end with the expected '.apk' extension.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser was unable to retrieve the\n     * AndroidManifest.xml file.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser encountered an unexpected\n     * exception.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser did not find any\n     * certificates in the .apk.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser found inconsistent\n     * certificates on the files in the .apk.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser encountered a\n     * CertificateEncodingException in one of the files in the .apk.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser encountered a bad or\n     * missing package name in the manifest.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser encountered a bad shared\n     * user id name in the manifest.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser encountered some structural\n     * problem in the manifest.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;\n\n    /**\n     * Installation parse return code: this is passed to the\n     * IPackageInstallObserver if the parser did not find any actionable\n     * tags (instrumentation or application) in the manifest.\n     *\n     * @hide\n     */\n    public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;\n\n    /**\n     * Installation failed return code: this is passed to the\n     * IPackageInstallObserver if the system failed to install the\n     * package because of system issues.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;\n\n    /**\n     * Installation failed return code: this is passed to the\n     * IPackageInstallObserver if the system failed to install the\n     * package because the user is restricted from installing apps.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_USER_RESTRICTED = -111;\n\n    /**\n     * Installation failed return code: this is passed to the\n     * IPackageInstallObserver if the system failed to install the\n     * package because it is attempting to define a permission that is already\n     * defined by some existing package.\n     * <p>\n     * The package name of the app which has already defined the permission is\n     * passed to a PackageInstallObserver, if any, as the\n     * EXTRA_FAILURE_EXISTING_PACKAGE string extra; and the name of the\n     * permission being redefined is passed in the\n     * EXTRA_FAILURE_EXISTING_PERMISSION string extra.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;\n\n    /**\n     * Installation failed return code: this is passed to the\n     * IPackageInstallObserver if the system failed to install the\n     * package because its packaged native code did not match any of the ABIs\n     * supported by the system.\n     *\n     * @hide\n     */\n    public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -113;\n\n    /**\n     * Internal return code for NativeLibraryHelper methods to indicate that the package\n     * being processed did not contain any native code. This is placed here only so that\n     * it can belong to the same value space as the other install failure codes.\n     *\n     * @hide\n     */\n    public static final int NO_NATIVE_LIBRARIES = -114;\n\n    /** {@hide} */\n    public static final int INSTALL_FAILED_ABORTED = -115;\n\n    /**\n     * Installation failed return code: ephemeral app installs are incompatible with some\n     * other installation flags supplied for the operation; or other circumstances such\n     * as trying to upgrade a system app via an ephemeral install.\n     * @hide\n     */\n    public static final int INSTALL_FAILED_EPHEMERAL_INVALID = -116;\n\n    \n    \n    \n    /**\n            * Return code for when package deletion succeeds. This is passed to the\n     * IPackageDeleteObserver if the system succeeded in deleting the\n     * package.\n             *\n             * @hide\n     */\n    public static final int DELETE_SUCCEEDED = 1;\n\n    /**\n     * Deletion failed return code: this is passed to the\n     * IPackageDeleteObserver if the system failed to delete the package\n     * for an unspecified reason.\n     *\n     * @hide\n     */\n    public static final int DELETE_FAILED_INTERNAL_ERROR = -1;\n\n    /**\n     * Deletion failed return code: this is passed to the\n     * IPackageDeleteObserver if the system failed to delete the package\n     * because it is the active DevicePolicy manager.\n     *\n     * @hide\n     */\n    public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;\n\n    /**\n     * Deletion failed return code: this is passed to the\n     * IPackageDeleteObserver if the system failed to delete the package\n     * since the user is restricted.\n     *\n     * @hide\n     */\n    public static final int DELETE_FAILED_USER_RESTRICTED = -3;\n\n    /**\n     * Deletion failed return code: this is passed to the\n     * IPackageDeleteObserver if the system failed to delete the package\n     * because a profile or device owner has marked the package as\n     * uninstallable.\n     *\n     * @hide\n     */\n    public static final int DELETE_FAILED_OWNER_BLOCKED = -4;\n\n    /** {@hide} */\n    public static final int DELETE_FAILED_ABORTED = -5;\n\n    /**\n     * Return code that is passed to the IPackageMoveObserver when the\n     * package has been successfully moved by the system.\n     *\n     * @hide\n     */\n    public static final int MOVE_SUCCEEDED = -100;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver when the\n     * package hasn't been successfully moved by the system because of\n     * insufficient memory on specified media.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_INSUFFICIENT_STORAGE = -1;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package doesn't exist.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_DOESNT_EXIST = -2;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package cannot be moved since its a system package.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_SYSTEM_PACKAGE = -3;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package cannot be moved since its forward locked.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_FORWARD_LOCKED = -4;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package cannot be moved to the specified location.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_INVALID_LOCATION = -5;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package cannot be moved to the specified location.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_INTERNAL_ERROR = -6;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package already has an operation pending in the queue.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_OPERATION_PENDING = -7;\n\n    /**\n     * Error code that is passed to the IPackageMoveObserver if the\n     * specified package cannot be moved since it contains a device admin.\n     *\n     * @hide\n     */\n    public static final int MOVE_FAILED_DEVICE_ADMIN = -8;\n\n\n    public static String installStatusToString(int status, String msg) {\n        final String str = installStatusToString(status);\n        if (msg != null) {\n            return str + \": \" + msg;\n        } else {\n            return str;\n        }\n    }\n\n    /** {@hide} */\n    public static String installStatusToString(int status) {\n        switch (status) {\n            case INSTALL_SUCCEEDED: return \"INSTALL_SUCCEEDED\";\n            case INSTALL_FAILED_ALREADY_EXISTS: return \"INSTALL_FAILED_ALREADY_EXISTS\";\n            case INSTALL_FAILED_INVALID_APK: return \"INSTALL_FAILED_INVALID_APK\";\n            case INSTALL_FAILED_INVALID_URI: return \"INSTALL_FAILED_INVALID_URI\";\n            case INSTALL_FAILED_INSUFFICIENT_STORAGE: return \"INSTALL_FAILED_INSUFFICIENT_STORAGE\";\n            case INSTALL_FAILED_DUPLICATE_PACKAGE: return \"INSTALL_FAILED_DUPLICATE_PACKAGE\";\n            case INSTALL_FAILED_NO_SHARED_USER: return \"INSTALL_FAILED_NO_SHARED_USER\";\n            case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return \"INSTALL_FAILED_UPDATE_INCOMPATIBLE\";\n            case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return \"INSTALL_FAILED_SHARED_USER_INCOMPATIBLE\";\n            case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return \"INSTALL_FAILED_MISSING_SHARED_LIBRARY\";\n            case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return \"INSTALL_FAILED_REPLACE_COULDNT_DELETE\";\n            case INSTALL_FAILED_DEXOPT: return \"INSTALL_FAILED_DEXOPT\";\n            case INSTALL_FAILED_OLDER_SDK: return \"INSTALL_FAILED_OLDER_SDK\";\n            case INSTALL_FAILED_CONFLICTING_PROVIDER: return \"INSTALL_FAILED_CONFLICTING_PROVIDER\";\n            case INSTALL_FAILED_NEWER_SDK: return \"INSTALL_FAILED_NEWER_SDK\";\n            case INSTALL_FAILED_TEST_ONLY: return \"INSTALL_FAILED_TEST_ONLY\";\n            case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return \"INSTALL_FAILED_CPU_ABI_INCOMPATIBLE\";\n            case INSTALL_FAILED_MISSING_FEATURE: return \"INSTALL_FAILED_MISSING_FEATURE\";\n            case INSTALL_FAILED_CONTAINER_ERROR: return \"INSTALL_FAILED_CONTAINER_ERROR\";\n            case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return \"INSTALL_FAILED_INVALID_INSTALL_LOCATION\";\n            case INSTALL_FAILED_MEDIA_UNAVAILABLE: return \"INSTALL_FAILED_MEDIA_UNAVAILABLE\";\n            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return \"INSTALL_FAILED_VERIFICATION_TIMEOUT\";\n            case INSTALL_FAILED_VERIFICATION_FAILURE: return \"INSTALL_FAILED_VERIFICATION_FAILURE\";\n            case INSTALL_FAILED_PACKAGE_CHANGED: return \"INSTALL_FAILED_PACKAGE_CHANGED\";\n            case INSTALL_FAILED_UID_CHANGED: return \"INSTALL_FAILED_UID_CHANGED\";\n            case INSTALL_FAILED_VERSION_DOWNGRADE: return \"INSTALL_FAILED_VERSION_DOWNGRADE\";\n            case INSTALL_PARSE_FAILED_NOT_APK: return \"INSTALL_PARSE_FAILED_NOT_APK\";\n            case INSTALL_PARSE_FAILED_BAD_MANIFEST: return \"INSTALL_PARSE_FAILED_BAD_MANIFEST\";\n            case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return \"INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION\";\n            case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return \"INSTALL_PARSE_FAILED_NO_CERTIFICATES\";\n            case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return \"INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES\";\n            case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return \"INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING\";\n            case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return \"INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME\";\n            case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return \"INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID\";\n            case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return \"INSTALL_PARSE_FAILED_MANIFEST_MALFORMED\";\n            case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return \"INSTALL_PARSE_FAILED_MANIFEST_EMPTY\";\n            case INSTALL_FAILED_INTERNAL_ERROR: return \"INSTALL_FAILED_INTERNAL_ERROR\";\n            case INSTALL_FAILED_USER_RESTRICTED: return \"INSTALL_FAILED_USER_RESTRICTED\";\n            case INSTALL_FAILED_DUPLICATE_PERMISSION: return \"INSTALL_FAILED_DUPLICATE_PERMISSION\";\n            case INSTALL_FAILED_NO_MATCHING_ABIS: return \"INSTALL_FAILED_NO_MATCHING_ABIS\";\n            case INSTALL_FAILED_ABORTED: return \"INSTALL_FAILED_ABORTED\";\n            default: return Integer.toString(status);\n        }\n    }\n\n    /** {@hide} */\n    public static int installStatusToPublicStatus(int status) {\n        switch (status) {\n            case INSTALL_SUCCEEDED: return PackageInstaller.STATUS_SUCCESS;\n            case INSTALL_FAILED_ALREADY_EXISTS: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_INVALID_APK: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_INVALID_URI: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_INSUFFICIENT_STORAGE: return PackageInstaller.STATUS_FAILURE_STORAGE;\n            case INSTALL_FAILED_DUPLICATE_PACKAGE: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_NO_SHARED_USER: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_DEXOPT: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_OLDER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_CONFLICTING_PROVIDER: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_NEWER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_TEST_ONLY: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_MISSING_FEATURE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_CONTAINER_ERROR: return PackageInstaller.STATUS_FAILURE_STORAGE;\n            case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return PackageInstaller.STATUS_FAILURE_STORAGE;\n            case INSTALL_FAILED_MEDIA_UNAVAILABLE: return PackageInstaller.STATUS_FAILURE_STORAGE;\n            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return PackageInstaller.STATUS_FAILURE_ABORTED;\n            case INSTALL_FAILED_VERIFICATION_FAILURE: return PackageInstaller.STATUS_FAILURE_ABORTED;\n            case INSTALL_FAILED_PACKAGE_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_UID_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_VERSION_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_NOT_APK: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_BAD_MANIFEST: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID;\n            case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;\n            case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;\n            case INSTALL_FAILED_NO_MATCHING_ABIS: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n            case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;\n            default: return PackageInstaller.STATUS_FAILURE;\n        }\n    }\n\n\n    public static String deleteStatusToString(boolean status) {\n        return status ? \"DELETE_SUCCEEDED\" : \"DELETE_FAILED\";\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallInfo.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\n/**\n * @author Lody\n */\n\npublic class PackageInstallInfo {\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallObserver.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\nimport android.content.Intent;\nimport android.content.pm.IPackageInstallObserver2;\nimport android.os.Bundle;\n\npublic class PackageInstallObserver {\n    private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {\n        @Override\n        public void onUserActionRequired(Intent intent) {\n            PackageInstallObserver.this.onUserActionRequired(intent);\n        }\n\n        @Override\n        public void onPackageInstalled(String basePackageName, int returnCode,\n                                       String msg, Bundle extras) {\n            PackageInstallObserver.this.onPackageInstalled(basePackageName, returnCode, msg,\n                    extras);\n        }\n    };\n\n    /**\n     * {@hide}\n     */\n    public IPackageInstallObserver2 getBinder() {\n        return mBinder;\n    }\n\n    public void onUserActionRequired(Intent intent) {\n    }\n\n    /**\n     * This method will be called to report the result of the package\n     * installation attempt.\n     *\n     * @param basePackageName Name of the package whose installation was\n     *                        attempted\n     * @param extras          If non-null, this Bundle contains extras providing\n     *                        additional information about an install failure. See\n     *                        {@link android.content.pm.PackageManager} for documentation\n     *                        about which extras apply to various failures; in particular\n     *                        the strings named EXTRA_FAILURE_*.\n     * @param returnCode      The numeric success or failure code indicating the\n     *                        basic outcome\n     * @hide\n     */\n    public void onPackageInstalled(String basePackageName, int returnCode, String msg,\n                                   Bundle extras) {\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.content.pm.IPackageInstallObserver2;\nimport android.content.pm.IPackageInstallerSession;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.system.OsConstants;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.remote.InstallResult;\nimport com.lody.virtual.server.pm.VAppManagerService;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static android.system.OsConstants.O_CREAT;\nimport static android.system.OsConstants.O_RDONLY;\nimport static android.system.OsConstants.O_WRONLY;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class PackageInstallerSession extends IPackageInstallerSession.Stub {\n\n    public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;\n    public static final int INSTALL_FAILED_ABORTED = -115;\n    public static final int INSTALL_SUCCEEDED = 1;\n    public static final int INSTALL_FAILED_INVALID_APK = -2;\n\n    private static final String TAG = \"PackageInstaller\";\n    private static final String REMOVE_SPLIT_MARKER_EXTENSION = \".removed\";\n\n    private static final int MSG_COMMIT = 0;\n\n\n    private final VPackageInstallerService.InternalCallback mCallback;\n    private final Context mContext;\n    private final Handler mHandler;\n\n    final int sessionId;\n    final int userId;\n    final int installerUid;\n\n    final SessionParams params;\n    final String installerPackageName;\n    private boolean mPermissionsAccepted;\n\n    /**\n     * Staging location where client data is written.\n     */\n    final File stageDir;\n\n    private final AtomicInteger mActiveCount = new AtomicInteger();\n\n    private final Object mLock = new Object();\n\n    private float mClientProgress = 0;\n    private float mInternalProgress = 0;\n    private float mProgress = 0;\n    private float mReportedProgress = -1;\n    private boolean mPrepared = false;\n    private boolean mSealed = false;\n    private boolean mDestroyed = false;\n    private int mFinalStatus;\n    private String mFinalMessage;\n\n    private IPackageInstallObserver2 mRemoteObserver;\n\n    private ArrayList<FileBridge> mBridges = new ArrayList<>();\n\n    private File mResolvedStageDir;\n\n    /**\n     * Fields derived from commit parsing\n     */\n    private String mPackageName;\n\n    private File mResolvedBaseFile;\n    private final List<File> mResolvedStagedFiles = new ArrayList<>();\n\n\n    private final Handler.Callback mHandlerCallback = new Handler.Callback() {\n        @Override\n        public boolean handleMessage(Message msg) {\n            synchronized (mLock) {\n                if (msg.obj != null) {\n                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;\n                }\n                try {\n                    commitLocked();\n                } catch (PackageManagerException e) {\n                    final String completeMsg = getCompleteMessage(e);\n                    VLog.e(TAG, \"Commit of session \" + sessionId + \" failed: \" + completeMsg);\n                    destroyInternal();\n                    dispatchSessionFinished(e.error, completeMsg, null);\n                }\n\n                return true;\n            }\n        }\n    };\n\n    public PackageInstallerSession(VPackageInstallerService.InternalCallback callback, Context context, Looper looper, String installerPackageName, int sessionId, int userId, int installerUid, SessionParams params, File stageDir) {\n        this.mCallback = callback;\n        this.mContext = context;\n        this.mHandler = new Handler(looper, mHandlerCallback);\n        this.installerPackageName = installerPackageName;\n        this.sessionId = sessionId;\n        this.userId = userId;\n        this.installerUid = installerUid;\n        this.mPackageName = params.appPackageName;\n        this.params = params;\n        this.stageDir = stageDir;\n    }\n\n    public SessionInfo generateInfo() {\n        final SessionInfo info = new SessionInfo();\n        synchronized (mLock) {\n            info.sessionId = sessionId;\n            info.installerPackageName = installerPackageName;\n            info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?\n                    mResolvedBaseFile.getAbsolutePath() : null;\n            info.progress = mProgress;\n            info.sealed = mSealed;\n            info.active = mActiveCount.get() > 0;\n\n            info.mode = params.mode;\n            info.sizeBytes = params.sizeBytes;\n            info.appPackageName = params.appPackageName;\n            info.appIcon = params.appIcon;\n            info.appLabel = params.appLabel;\n        }\n        return info;\n    }\n\n    private void commitLocked() throws PackageManagerException {\n        if (mDestroyed) {\n            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, \"Session destroyed\");\n        }\n        if (!mSealed) {\n            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, \"Session not sealed\");\n        }\n        try {\n            resolveStageDir();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        validateInstallLocked();\n        mInternalProgress = 0.5f;\n        computeProgressLocked(true);\n        // We've reached point of no return; call into PMS to install the stage.\n        // Regardless of success or failure we always destroy session.\n        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {\n            @Override\n            public void onUserActionRequired(Intent intent) {\n                throw new IllegalStateException();\n            }\n\n            @Override\n            public void onPackageInstalled(String basePackageName, int returnCode, String msg,\n                                           Bundle extras) {\n                destroyInternal();\n                dispatchSessionFinished(returnCode, msg, extras);\n            }\n        };\n\n        InstallResult installResult = VAppManagerService.get().installPackage(stageDir.getPath(), 0);\n        destroyInternal();\n        dispatchSessionFinished(installResult.isSuccess ? INSTALL_SUCCEEDED : INSTALL_FAILED_INTERNAL_ERROR, installResult.toString(), null);\n    }\n\n    private void validateInstallLocked() throws PackageManagerException {\n        mResolvedBaseFile = null;\n        mResolvedStagedFiles.clear();\n        File[] addedFiles = this.mResolvedStageDir.listFiles();\n        if (addedFiles == null || addedFiles.length == 0) {\n            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, \"No packages staged\");\n        }\n        for (File addedFile : addedFiles) {\n            if (!addedFile.isDirectory()) {\n                final String targetName = \"base.apk\";\n                final File targetFile = new File(mResolvedStageDir, targetName);\n                if (!addedFile.equals(targetFile)) {\n                    mResolvedStagedFiles.add(addedFile);\n                } else {\n                    mResolvedBaseFile = targetFile;\n                }\n            }\n        }\n        if (mResolvedBaseFile == null && mResolvedStagedFiles.isEmpty()) {\n            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,\n                    \"Full install must include a base package\");\n        }\n    }\n\n    @Override\n    public void setClientProgress(float progress) throws RemoteException {\n        synchronized (mLock) {\n            // Always publish first staging movement\n            final boolean forcePublish = (mClientProgress == 0);\n            mClientProgress = progress;\n            computeProgressLocked(forcePublish);\n        }\n    }\n\n\n    private static float constrain(float amount, float low, float high) {\n        return amount < low ? low : (amount > high ? high : amount);\n    }\n\n    private void computeProgressLocked(boolean forcePublish) {\n        mProgress = constrain(mClientProgress * 0.8f, 0f, 0.8f)\n                + constrain(mInternalProgress * 0.2f, 0f, 0.2f);\n\n        // Only publish when meaningful change\n        if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {\n            mReportedProgress = mProgress;\n            mCallback.onSessionProgressChanged(this, mProgress);\n        }\n    }\n\n    @Override\n    public void addClientProgress(float progress) throws RemoteException {\n        synchronized (mLock) {\n            setClientProgress(mClientProgress + progress);\n        }\n    }\n\n    @Override\n    public String[] getNames() throws RemoteException {\n        assertPreparedAndNotSealed(\"getNames\");\n        try {\n            return resolveStageDir().list();\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    /**\n     * Resolve the actual location where staged data should be written. This\n     * might point at an ASEC mount point, which is why we delay path resolution\n     * until someone actively works with the session.\n     */\n    private File resolveStageDir() throws IOException {\n        synchronized (mLock) {\n            if (mResolvedStageDir == null && stageDir != null) {\n                mResolvedStageDir = stageDir;\n                if (!stageDir.exists()) {\n                    stageDir.mkdirs();\n                }\n            }\n            return mResolvedStageDir;\n        }\n    }\n\n    @Override\n    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) throws RemoteException {\n        try {\n            return openWriteInternal(name, offsetBytes, lengthBytes);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private void assertPreparedAndNotSealed(String cookie) {\n        synchronized (mLock) {\n            if (!mPrepared) {\n                throw new IllegalStateException(cookie + \" before prepared\");\n            }\n            if (mSealed) {\n                throw new SecurityException(cookie + \" not allowed after commit\");\n            }\n        }\n    }\n\n\n    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)\n            throws IOException {\n        // Quick sanity check of state, and allocate a pipe for ourselves. We\n        // then do heavy disk allocation outside the lock, but this open pipe\n        // will block any attempted install transitions.\n        final FileBridge bridge;\n        synchronized (mLock) {\n            assertPreparedAndNotSealed(\"openWrite\");\n\n            bridge = new FileBridge();\n            mBridges.add(bridge);\n        }\n        try {\n            final File target = new File(resolveStageDir(), name);\n            // TODO: this should delegate to DCS so the system process avoids\n            // holding open FDs into containers.\n            final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),\n                    O_CREAT | O_WRONLY, 0644);\n            // If caller specified a total length, allocate it for them. Free up\n            // cache space to grow, if needed.\n            if (lengthBytes > 0) {\n                Os.posix_fallocate(targetFd, 0, lengthBytes);\n            }\n            if (offsetBytes > 0) {\n                Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);\n            }\n            bridge.setTargetFile(targetFd);\n            bridge.start();\n            return ParcelFileDescriptor.dup(bridge.getClientSocket());\n\n        } catch (ErrnoException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public ParcelFileDescriptor openRead(String name) throws RemoteException {\n        try {\n            return openReadInternal(name);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private ParcelFileDescriptor openReadInternal(String name) throws IOException {\n        assertPreparedAndNotSealed(\"openRead\");\n\n        try {\n            if (!FileUtils.isValidExtFilename(name)) {\n                throw new IllegalArgumentException(\"Invalid name: \" + name);\n            }\n            final File target = new File(resolveStageDir(), name);\n\n            final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);\n            return ParcelFileDescriptor.dup(targetFd);\n\n        } catch (ErrnoException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public void removeSplit(String splitName) throws RemoteException {\n        if (TextUtils.isEmpty(params.appPackageName)) {\n            throw new IllegalStateException(\"Must specify package name to remove a split\");\n        }\n        try {\n            createRemoveSplitMarker(splitName);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private void createRemoveSplitMarker(String splitName) throws IOException {\n        try {\n            final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;\n            if (!FileUtils.isValidExtFilename(markerName)) {\n                throw new IllegalArgumentException(\"Invalid marker: \" + markerName);\n            }\n            final File target = new File(resolveStageDir(), markerName);\n            target.createNewFile();\n            Os.chmod(target.getAbsolutePath(), 0 /*mode*/);\n        } catch (ErrnoException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public void close() throws RemoteException {\n        if (mActiveCount.decrementAndGet() == 0) {\n            mCallback.onSessionActiveChanged(this, false);\n        }\n    }\n\n    // https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:frameworks/base/core/java/android/content/pm/IPackageInstallerSession.aidl;l=39\n    public void commit(IntentSender statusReceiver, boolean forTransferred) throws RemoteException {\n        commit(statusReceiver);\n    }\n\n    @Override\n    public void commit(IntentSender statusReceiver) throws RemoteException {\n        final boolean wasSealed;\n        synchronized (mLock) {\n            wasSealed = mSealed;\n            if (!mSealed) {\n                // Verify that all writers are hands-off\n                for (FileBridge bridge : mBridges) {\n                    if (!bridge.isClosed()) {\n                        throw new SecurityException(\"Files still open\");\n                    }\n                }\n                mSealed = true;\n            }\n\n            // Client staging is fully done at this point\n            mClientProgress = 1f;\n            computeProgressLocked(true);\n        }\n\n        if (!wasSealed) {\n            // Persist the fact that we've sealed ourselves to prevent\n            // mutations of any hard links we create. We do this without holding\n            // the session lock, since otherwise it's a lock inversion.\n            mCallback.onSessionSealedBlocking(this);\n        }\n\n        // This ongoing commit should keep session active, even though client\n        // will probably close their end.\n        mActiveCount.incrementAndGet();\n\n        final VPackageInstallerService.PackageInstallObserverAdapter adapter\n                = new VPackageInstallerService.PackageInstallObserverAdapter(mContext,\n                statusReceiver, sessionId, userId);\n        mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();\n    }\n\n    @Override\n    public void abandon() throws RemoteException {\n        destroyInternal();\n        dispatchSessionFinished(INSTALL_FAILED_ABORTED, \"Session was abandoned\", null);\n    }\n\n    private void destroyInternal() {\n        synchronized (mLock) {\n            mSealed = true;\n            mDestroyed = true;\n\n            // Force shut down all bridges\n            for (FileBridge bridge : mBridges) {\n                bridge.forceClose();\n            }\n        }\n        if (stageDir != null) {\n            FileUtils.deleteDir(stageDir.getAbsolutePath());\n        }\n    }\n\n    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {\n        mFinalStatus = returnCode;\n        mFinalMessage = msg;\n\n        if (mRemoteObserver != null) {\n            try {\n                mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);\n            } catch (RemoteException ignored) {\n            }\n        }\n\n        final boolean success = (returnCode == INSTALL_SUCCEEDED);\n        mCallback.onSessionFinished(this, success);\n    }\n\n    void setPermissionsResult(boolean accepted) {\n        if (!mSealed) {\n            throw new SecurityException(\"Must be sealed to accept permissions\");\n        }\n\n        if (accepted) {\n            // Mark and kick off another install pass\n            synchronized (mLock) {\n                mPermissionsAccepted = true;\n            }\n            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();\n        } else {\n            destroyInternal();\n            dispatchSessionFinished(INSTALL_FAILED_ABORTED, \"User rejected permissions\", null);\n        }\n    }\n\n    public void open() throws IOException {\n        if (mActiveCount.getAndIncrement() == 0) {\n            mCallback.onSessionActiveChanged(this, true);\n        }\n\n        synchronized (mLock) {\n            if (!mPrepared) {\n                if (stageDir == null) {\n                    throw new IllegalArgumentException(\n                            \"Exactly one of stageDir or stageCid stage must be set\");\n                }\n                mPrepared = true;\n                mCallback.onSessionPrepared(this);\n            }\n        }\n    }\n\n\n    public static String getCompleteMessage(Throwable t) {\n        final StringBuilder builder = new StringBuilder();\n        builder.append(t.getMessage());\n        while ((t = t.getCause()) != null) {\n            builder.append(\": \").append(t.getMessage());\n        }\n        return builder.toString();\n    }\n\n    private class PackageManagerException extends Exception {\n        public final int error;\n\n        PackageManagerException(int error, String detailMessage) {\n            super(detailMessage);\n            this.error = error;\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/SessionInfo.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\nimport android.graphics.Bitmap;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport mirror.android.content.pm.PackageInstaller;\n\n/**\n * @author Lody\n */\n\npublic class SessionInfo implements Parcelable {\n    \n    public int sessionId;\n    public String installerPackageName;\n    public String resolvedBaseCodePath;\n    public float progress;\n    public boolean sealed;\n    public boolean active;\n    public int mode;\n    public long sizeBytes;\n    public String appPackageName;\n    public Bitmap appIcon;\n    public CharSequence appLabel;\n\n\n    public android.content.pm.PackageInstaller.SessionInfo alloc() {\n        android.content.pm.PackageInstaller.SessionInfo sessionInfo = PackageInstaller.SessionInfo.ctor.newInstance();\n        PackageInstaller.SessionInfo.sessionId.set(sessionInfo, sessionId);\n        PackageInstaller.SessionInfo.installerPackageName.set(sessionInfo, installerPackageName);\n        PackageInstaller.SessionInfo.resolvedBaseCodePath.set(sessionInfo, resolvedBaseCodePath);\n        PackageInstaller.SessionInfo.progress.set(sessionInfo, progress);\n        PackageInstaller.SessionInfo.sealed.set(sessionInfo, sealed);\n        PackageInstaller.SessionInfo.active.set(sessionInfo, active);\n        PackageInstaller.SessionInfo.mode.set(sessionInfo, mode);\n        PackageInstaller.SessionInfo.sizeBytes.set(sessionInfo, sizeBytes);\n        PackageInstaller.SessionInfo.appPackageName.set(sessionInfo, appPackageName);\n        PackageInstaller.SessionInfo.appIcon.set(sessionInfo, appIcon);\n        PackageInstaller.SessionInfo.appLabel.set(sessionInfo, appLabel);\n        return sessionInfo;\n    }\n\n    public static SessionInfo realloc(android.content.pm.PackageInstaller.SessionInfo sessionInfo) {\n        SessionInfo info = new SessionInfo();\n        info.sessionId = PackageInstaller.SessionInfo.sessionId.get(sessionInfo);\n        info.installerPackageName = PackageInstaller.SessionInfo.installerPackageName.get(sessionInfo);\n        info.resolvedBaseCodePath = PackageInstaller.SessionInfo.resolvedBaseCodePath.get(sessionInfo);\n        info.progress = PackageInstaller.SessionInfo.progress.get(sessionInfo);\n        info.sealed = PackageInstaller.SessionInfo.sealed.get(sessionInfo);\n        info.active = PackageInstaller.SessionInfo.active.get(sessionInfo);\n        info.mode = PackageInstaller.SessionInfo.mode.get(sessionInfo);\n        info.sizeBytes = PackageInstaller.SessionInfo.sizeBytes.get(sessionInfo);\n        info.appPackageName = PackageInstaller.SessionInfo.appPackageName.get(sessionInfo);\n        info.appIcon = PackageInstaller.SessionInfo.appIcon.get(sessionInfo);\n        info.appLabel = PackageInstaller.SessionInfo.appLabel.get(sessionInfo);\n        return info;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.sessionId);\n        dest.writeString(this.installerPackageName);\n        dest.writeString(this.resolvedBaseCodePath);\n        dest.writeFloat(this.progress);\n        dest.writeByte(this.sealed ? (byte) 1 : (byte) 0);\n        dest.writeByte(this.active ? (byte) 1 : (byte) 0);\n        dest.writeInt(this.mode);\n        dest.writeLong(this.sizeBytes);\n        dest.writeString(this.appPackageName);\n        dest.writeParcelable(this.appIcon, flags);\n        if (appLabel != null) {\n            dest.writeString(appLabel.toString());\n        }\n    }\n\n    public SessionInfo() {\n    }\n\n    protected SessionInfo(Parcel in) {\n        this.sessionId = in.readInt();\n        this.installerPackageName = in.readString();\n        this.resolvedBaseCodePath = in.readString();\n        this.progress = in.readFloat();\n        this.sealed = in.readByte() != 0;\n        this.active = in.readByte() != 0;\n        this.mode = in.readInt();\n        this.sizeBytes = in.readLong();\n        this.appPackageName = in.readString();\n        this.appIcon = in.readParcelable(Bitmap.class.getClassLoader());\n        this.appLabel = in.readString();\n    }\n\n    public static final Parcelable.Creator<SessionInfo> CREATOR = new Parcelable.Creator<SessionInfo>() {\n        @Override\n        public SessionInfo createFromParcel(Parcel source) {\n            return new SessionInfo(source);\n        }\n\n        @Override\n        public SessionInfo[] newArray(int size) {\n            return new SessionInfo[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/SessionParams.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\n\nimport android.annotation.TargetApi;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport mirror.android.content.pm.PackageInstaller.SessionParamsLOLLIPOP;\nimport mirror.android.content.pm.PackageInstaller.SessionParamsMarshmallow;\n\n\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class SessionParams implements Parcelable {\n\n    public static final int MODE_INVALID = -1;\n\n    /**\n     * Mode for an install session whose staged APKs should fully replace any\n     * existing APKs for the target app.\n     */\n    public static final int MODE_FULL_INSTALL = 1;\n\n    /**\n     * Mode for an install session that should inherit any existing APKs for the\n     * target app, unless they have been explicitly overridden (based on split\n     * name) by the session. For example, this can be used to add one or more\n     * split APKs to an existing installation.\n     * <p>\n     * If there are no existing APKs for the target app, this behaves like\n     * {@link #MODE_FULL_INSTALL}.\n     */\n    public static final int MODE_INHERIT_EXISTING = 2;\n\n    public int mode = MODE_INVALID;\n    public int installFlags;\n    public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;\n    public long sizeBytes = -1;\n    public String appPackageName;\n    public Bitmap appIcon;\n    public String appLabel;\n    public long appIconLastModified = -1;\n    public Uri originatingUri;\n    public Uri referrerUri;\n    public String abiOverride;\n    public String volumeUuid;\n    public String[] grantedRuntimePermissions;\n\n    public SessionParams(int mode) {\n        this.mode = mode;\n    }\n\n\n    public PackageInstaller.SessionParams build() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(mode);\n            SessionParamsMarshmallow.installFlags.set(params, installFlags);\n            SessionParamsMarshmallow.installLocation.set(params, installLocation);\n            SessionParamsMarshmallow.sizeBytes.set(params, sizeBytes);\n            SessionParamsMarshmallow.appPackageName.set(params, appPackageName);\n            SessionParamsMarshmallow.appIcon.set(params, appIcon);\n            SessionParamsMarshmallow.appLabel.set(params, appLabel);\n            SessionParamsMarshmallow.appIconLastModified.set(params, appIconLastModified);\n            SessionParamsMarshmallow.originatingUri.set(params, originatingUri);\n            SessionParamsMarshmallow.referrerUri.set(params, referrerUri);\n            SessionParamsMarshmallow.abiOverride.set(params, abiOverride);\n            SessionParamsMarshmallow.volumeUuid.set(params, volumeUuid);\n            SessionParamsMarshmallow.grantedRuntimePermissions.set(params, grantedRuntimePermissions);\n            return params;\n        }\n        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(mode);\n        SessionParamsLOLLIPOP.installFlags.set(params, installFlags);\n        SessionParamsLOLLIPOP.installLocation.set(params, installLocation);\n        SessionParamsLOLLIPOP.sizeBytes.set(params, sizeBytes);\n        SessionParamsLOLLIPOP.appPackageName.set(params, appPackageName);\n        SessionParamsLOLLIPOP.appIcon.set(params, appIcon);\n        SessionParamsLOLLIPOP.appLabel.set(params, appLabel);\n        SessionParamsLOLLIPOP.appIconLastModified.set(params, appIconLastModified);\n        SessionParamsLOLLIPOP.originatingUri.set(params, originatingUri);\n        SessionParamsLOLLIPOP.referrerUri.set(params, referrerUri);\n        SessionParamsLOLLIPOP.abiOverride.set(params, abiOverride);\n        return params;\n    }\n\n    public static SessionParams create(PackageInstaller.SessionParams sessionParams) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            SessionParams params = new SessionParams(SessionParamsMarshmallow.mode.get(sessionParams));\n            params.installFlags = SessionParamsMarshmallow.installFlags.get(sessionParams);\n            params.installLocation = SessionParamsMarshmallow.installLocation.get(sessionParams);\n            params.sizeBytes = SessionParamsMarshmallow.sizeBytes.get(sessionParams);\n            params.appPackageName = SessionParamsMarshmallow.appPackageName.get(sessionParams);\n            params.appIcon = SessionParamsMarshmallow.appIcon.get(sessionParams);\n            params.appLabel = SessionParamsMarshmallow.appLabel.get(sessionParams);\n            params.appIconLastModified = SessionParamsMarshmallow.appIconLastModified.get(sessionParams);\n            params.originatingUri = SessionParamsMarshmallow.originatingUri.get(sessionParams);\n            params.referrerUri = SessionParamsMarshmallow.referrerUri.get(sessionParams);\n            params.abiOverride = SessionParamsMarshmallow.abiOverride.get(sessionParams);\n            params.volumeUuid = SessionParamsMarshmallow.volumeUuid.get(sessionParams);\n            params.grantedRuntimePermissions = SessionParamsMarshmallow.grantedRuntimePermissions.get(sessionParams);\n            return params;\n        }\n        SessionParams params = new SessionParams(SessionParamsLOLLIPOP.mode.get(sessionParams));\n        params.installFlags = SessionParamsLOLLIPOP.installFlags.get(sessionParams);\n        params.installLocation = SessionParamsLOLLIPOP.installLocation.get(sessionParams);\n        params.sizeBytes = SessionParamsLOLLIPOP.sizeBytes.get(sessionParams);\n        params.appPackageName = SessionParamsLOLLIPOP.appPackageName.get(sessionParams);\n        params.appIcon = SessionParamsLOLLIPOP.appIcon.get(sessionParams);\n        params.appLabel = SessionParamsLOLLIPOP.appLabel.get(sessionParams);\n        params.appIconLastModified = SessionParamsLOLLIPOP.appIconLastModified.get(sessionParams);\n        params.originatingUri = SessionParamsLOLLIPOP.originatingUri.get(sessionParams);\n        params.referrerUri = SessionParamsLOLLIPOP.referrerUri.get(sessionParams);\n        params.abiOverride = SessionParamsLOLLIPOP.abiOverride.get(sessionParams);\n        return params;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.mode);\n        dest.writeInt(this.installFlags);\n        dest.writeInt(this.installLocation);\n        dest.writeLong(this.sizeBytes);\n        dest.writeString(this.appPackageName);\n        dest.writeParcelable(this.appIcon, flags);\n        dest.writeString(this.appLabel);\n        dest.writeLong(this.appIconLastModified);\n        dest.writeParcelable(this.originatingUri, flags);\n        dest.writeParcelable(this.referrerUri, flags);\n        dest.writeString(this.abiOverride);\n        dest.writeString(this.volumeUuid);\n        dest.writeStringArray(this.grantedRuntimePermissions);\n    }\n\n    protected SessionParams(Parcel in) {\n        this.mode = in.readInt();\n        this.installFlags = in.readInt();\n        this.installLocation = in.readInt();\n        this.sizeBytes = in.readLong();\n        this.appPackageName = in.readString();\n        this.appIcon = in.readParcelable(Bitmap.class.getClassLoader());\n        this.appLabel = in.readString();\n        this.appIconLastModified = in.readLong();\n        this.originatingUri = in.readParcelable(Uri.class.getClassLoader());\n        this.referrerUri = in.readParcelable(Uri.class.getClassLoader());\n        this.abiOverride = in.readString();\n        this.volumeUuid = in.readString();\n        this.grantedRuntimePermissions = in.createStringArray();\n    }\n\n    public static final Parcelable.Creator<SessionParams> CREATOR = new Parcelable.Creator<SessionParams>() {\n        @Override\n        public SessionParams createFromParcel(Parcel source) {\n            return new SessionParams(source);\n        }\n\n        @Override\n        public SessionParams[] newArray(int size) {\n            return new SessionParams[size];\n        }\n    };\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/VPackageInstallerService.java",
    "content": "package com.lody.virtual.server.pm.installer;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentSender;\nimport android.content.pm.IPackageInstallerCallback;\nimport android.content.pm.IPackageInstallerSession;\nimport android.content.pm.PackageInstaller;\nimport android.graphics.Bitmap;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.helper.compat.ObjectsCompat;\nimport com.lody.virtual.helper.utils.Singleton;\nimport com.lody.virtual.os.VBinder;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.os.VUserHandle;\nimport com.lody.virtual.remote.VParceledListSlice;\nimport com.lody.virtual.server.IPackageInstaller;\nimport com.lody.virtual.server.pm.VAppManagerService;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.security.SecureRandom;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\nimport static com.lody.virtual.server.pm.installer.PackageHelper.installStatusToPublicStatus;\nimport static com.lody.virtual.server.pm.installer.PackageHelper.installStatusToString;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class VPackageInstallerService extends IPackageInstaller.Stub {\n\n    private static final String TAG = \"PackageInstaller\";\n\n    /**\n     * Upper bound on number of active sessions for a UID\n     */\n    private static final long MAX_ACTIVE_SESSIONS = 1024;\n    private static final Singleton<VPackageInstallerService> gDefault = new Singleton<VPackageInstallerService>() {\n        @Override\n        protected VPackageInstallerService create() {\n            return new VPackageInstallerService();\n        }\n    };\n    /**\n     * Used for generating session IDs. Since this is created at boot time,\n     * normal random might be predictable.\n     */\n    private final Random mRandom = new SecureRandom();\n    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();\n    private final Handler mInstallHandler;\n    private final Callbacks mCallbacks;\n    private final HandlerThread mInstallThread;\n    private final InternalCallback mInternalCallback = new InternalCallback();\n    private Context mContext;\n\n    private VPackageInstallerService() {\n        mContext = VirtualCore.get().getContext();\n        mInstallThread = new HandlerThread(\"PackageInstaller\");\n        mInstallThread.start();\n        mInstallHandler = new Handler(mInstallThread.getLooper());\n        mCallbacks = new Callbacks(mInstallThread.getLooper());\n    }\n\n    public static VPackageInstallerService get() {\n        return gDefault.get();\n    }\n\n    private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,\n                                       int installerUid) {\n        int count = 0;\n        final int size = sessions.size();\n        for (int i = 0; i < size; i++) {\n            final PackageInstallerSession session = sessions.valueAt(i);\n            if (session.installerUid == installerUid) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    @Override\n    public int createSession(SessionParams params, String installerPackageName, int userId) throws RemoteException {\n        try {\n            return createSessionInternal(params, installerPackageName, userId);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private int createSessionInternal(SessionParams params, String installerPackageName, int userId)\n            throws IOException {\n        final int callingUid = VBinder.getCallingUid();\n        final int sessionId;\n        final PackageInstallerSession session;\n        synchronized (mSessions) {\n            // Sanity check that installer isn't going crazy\n            final int activeCount = getSessionCount(mSessions, callingUid);\n            if (activeCount >= MAX_ACTIVE_SESSIONS) {\n                throw new IllegalStateException(\n                        \"Too many active sessions for UID \" + callingUid);\n            }\n            sessionId = allocateSessionIdLocked();\n            File sessionDir = new File(VEnvironment.getPackageInstallerStageDir(), \"vmd-\" + sessionId);\n            session = new PackageInstallerSession(mInternalCallback, mContext, mInstallHandler.getLooper(), installerPackageName, sessionId, userId, callingUid, params, sessionDir);\n        }\n        synchronized (mSessions) {\n            mSessions.put(sessionId, session);\n        }\n        mCallbacks.notifySessionCreated(session.sessionId, session.userId);\n        return sessionId;\n    }\n\n    @Override\n    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {\n        synchronized (mSessions) {\n            final PackageInstallerSession session = mSessions.get(sessionId);\n            if (session == null || !isCallingUidOwner(session)) {\n                throw new SecurityException(\"Caller has no access to session \" + sessionId);\n            }\n\n            session.params.appIcon = appIcon;\n            session.params.appIconLastModified = -1;\n\n            mInternalCallback.onSessionBadgingChanged(session);\n        }\n    }\n\n    @Override\n    public void updateSessionAppLabel(int sessionId, String appLabel) throws RemoteException {\n        synchronized (mSessions) {\n            final PackageInstallerSession session = mSessions.get(sessionId);\n            if (session == null || !isCallingUidOwner(session)) {\n                throw new SecurityException(\"Caller has no access to session \" + sessionId);\n            }\n            session.params.appLabel = appLabel;\n            mInternalCallback.onSessionBadgingChanged(session);\n        }\n    }\n\n    @Override\n    public void abandonSession(int sessionId) throws RemoteException {\n        synchronized (mSessions) {\n            final PackageInstallerSession session = mSessions.get(sessionId);\n            if (session == null || !isCallingUidOwner(session)) {\n                throw new SecurityException(\"Caller has no access to session \" + sessionId);\n            }\n            session.abandon();\n        }\n    }\n\n    @Override\n    public IPackageInstallerSession openSession(int sessionId) throws RemoteException {\n        try {\n            return openSessionInternal(sessionId);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {\n        synchronized (mSessions) {\n            final PackageInstallerSession session = mSessions.get(sessionId);\n            if (session == null || !isCallingUidOwner(session)) {\n                throw new SecurityException(\"Caller has no access to session \" + sessionId);\n            }\n            session.open();\n            return session;\n        }\n    }\n\n    @Override\n    public SessionInfo getSessionInfo(int sessionId) throws RemoteException {\n        synchronized (mSessions) {\n            final PackageInstallerSession session = mSessions.get(sessionId);\n            return session != null ? session.generateInfo() : null;\n        }\n    }\n\n    @Override\n    public VParceledListSlice getAllSessions(int userId) throws RemoteException {\n        final List<SessionInfo> result = new ArrayList<>();\n        synchronized (mSessions) {\n            for (int i = 0; i < mSessions.size(); i++) {\n                final PackageInstallerSession session = mSessions.valueAt(i);\n                if (session.userId == userId) {\n                    result.add(session.generateInfo());\n                }\n            }\n        }\n        return new VParceledListSlice<>(result);\n    }\n\n    @Override\n    public VParceledListSlice getMySessions(String installerPackageName, int userId) throws RemoteException {\n        final List<SessionInfo> result = new ArrayList<>();\n        synchronized (mSessions) {\n            for (int i = 0; i < mSessions.size(); i++) {\n                final PackageInstallerSession session = mSessions.valueAt(i);\n                if (ObjectsCompat.equals(session.installerPackageName, installerPackageName)\n                        && session.userId == userId) {\n                    result.add(session.generateInfo());\n                }\n            }\n        }\n        return new VParceledListSlice<>(result);\n    }\n\n    @Override\n    public void registerCallback(IPackageInstallerCallback callback, int userId) throws RemoteException {\n        mCallbacks.register(callback, userId);\n    }\n\n    @Override\n    public void unregisterCallback(IPackageInstallerCallback callback) throws RemoteException {\n        mCallbacks.unregister(callback);\n    }\n\n    @Override\n    public void uninstall(String packageName, String callerPackageName, int flags, IntentSender statusReceiver, int userId) throws RemoteException {\n        boolean success = VAppManagerService.get().uninstallPackage(packageName);\n        if (statusReceiver != null) {\n            final Intent fillIn = new Intent();\n            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);\n            fillIn.putExtra(PackageInstaller.EXTRA_STATUS, success ? PackageInstaller.STATUS_SUCCESS : PackageInstaller.STATUS_FAILURE);\n            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, PackageHelper.deleteStatusToString(success));\n            fillIn.putExtra(\"android.content.pm.extra.LEGACY_STATUS\", success ? 1 : -1);\n            try {\n                statusReceiver.sendIntent(mContext, 0, fillIn, null, null);\n            } catch (IntentSender.SendIntentException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Override\n    public void setPermissionsResult(int sessionId, boolean accepted) throws RemoteException {\n        synchronized (mSessions) {\n            PackageInstallerSession session = mSessions.get(sessionId);\n            if (session != null) {\n                session.setPermissionsResult(accepted);\n            }\n        }\n    }\n\n    private boolean isCallingUidOwner(PackageInstallerSession session) {\n        return true;\n    }\n\n    private int allocateSessionIdLocked() {\n        int n = 0;\n        int sessionId;\n        do {\n            sessionId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;\n            if (mSessions.get(sessionId) == null) {\n                return sessionId;\n            }\n        } while (n++ < 32);\n\n        throw new IllegalStateException(\"Failed to allocate session ID\");\n    }\n\n    private static class Callbacks extends Handler {\n        private static final int MSG_SESSION_CREATED = 1;\n        private static final int MSG_SESSION_BADGING_CHANGED = 2;\n        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;\n        private static final int MSG_SESSION_PROGRESS_CHANGED = 4;\n        private static final int MSG_SESSION_FINISHED = 5;\n\n        private final RemoteCallbackList<IPackageInstallerCallback>\n                mCallbacks = new RemoteCallbackList<>();\n\n        public Callbacks(Looper looper) {\n            super(looper);\n        }\n\n        public void register(IPackageInstallerCallback callback, int userId) {\n            mCallbacks.register(callback, new VUserHandle(userId));\n        }\n\n        public void unregister(IPackageInstallerCallback callback) {\n            mCallbacks.unregister(callback);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            final int userId = msg.arg2;\n            final int n = mCallbacks.beginBroadcast();\n            for (int i = 0; i < n; i++) {\n                final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);\n                final VUserHandle user = (VUserHandle) mCallbacks.getBroadcastCookie(i);\n                // TODO: dispatch notifications for slave profiles\n                if (userId == user.getIdentifier()) {\n                    try {\n                        invokeCallback(callback, msg);\n                    } catch (RemoteException ignored) {\n                    }\n                }\n            }\n            mCallbacks.finishBroadcast();\n        }\n\n        private void invokeCallback(IPackageInstallerCallback callback, Message msg)\n                throws RemoteException {\n            final int sessionId = msg.arg1;\n            switch (msg.what) {\n                case MSG_SESSION_CREATED:\n                    callback.onSessionCreated(sessionId);\n                    break;\n                case MSG_SESSION_BADGING_CHANGED:\n                    callback.onSessionBadgingChanged(sessionId);\n                    break;\n                case MSG_SESSION_ACTIVE_CHANGED:\n                    callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);\n                    break;\n                case MSG_SESSION_PROGRESS_CHANGED:\n                    callback.onSessionProgressChanged(sessionId, (float) msg.obj);\n                    break;\n                case MSG_SESSION_FINISHED:\n                    callback.onSessionFinished(sessionId, (boolean) msg.obj);\n                    break;\n            }\n        }\n\n        private void notifySessionCreated(int sessionId, int userId) {\n            obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget();\n        }\n\n        private void notifySessionBadgingChanged(int sessionId, int userId) {\n            obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();\n        }\n\n        private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {\n            obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();\n        }\n\n        private void notifySessionProgressChanged(int sessionId, int userId, float progress) {\n            obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();\n        }\n\n        public void notifySessionFinished(int sessionId, int userId, boolean success) {\n            obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();\n        }\n    }\n\n    static class PackageInstallObserverAdapter extends PackageInstallObserver {\n        private final Context mContext;\n        private final IntentSender mTarget;\n        private final int mSessionId;\n        private final int mUserId;\n\n        PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId, int userId) {\n            mContext = context;\n            mTarget = target;\n            mSessionId = sessionId;\n            mUserId = userId;\n        }\n\n        @Override\n        public void onUserActionRequired(Intent intent) {\n            final Intent fillIn = new Intent();\n            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);\n            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,\n                    PackageInstaller.STATUS_PENDING_USER_ACTION);\n            fillIn.putExtra(Intent.EXTRA_INTENT, intent);\n            try {\n                mTarget.sendIntent(mContext, 0, fillIn, null, null);\n            } catch (IntentSender.SendIntentException ignored) {\n            }\n        }\n\n        @Override\n        public void onPackageInstalled(String basePackageName, int returnCode, String msg,\n                                       Bundle extras) {\n            final Intent fillIn = new Intent();\n            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);\n            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);\n            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,\n                    installStatusToPublicStatus(returnCode));\n            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,\n                    installStatusToString(returnCode, msg));\n            fillIn.putExtra(\"android.content.pm.extra.LEGACY_STATUS\", returnCode);\n            if (extras != null) {\n                final String existing = extras.getString(\"android.content.pm.extra.FAILURE_EXISTING_PACKAGE\");\n                if (!TextUtils.isEmpty(existing)) {\n                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);\n                }\n            }\n            try {\n                mTarget.sendIntent(mContext, 0, fillIn, null, null);\n            } catch (IntentSender.SendIntentException ignored) {\n            }\n        }\n    }\n\n    class InternalCallback {\n        public void onSessionBadgingChanged(PackageInstallerSession session) {\n            mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);\n        }\n\n        public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {\n            mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);\n        }\n\n        public void onSessionProgressChanged(PackageInstallerSession session, float progress) {\n            mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);\n        }\n\n        public void onSessionFinished(final PackageInstallerSession session, boolean success) {\n            mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);\n\n            mInstallHandler.post(new Runnable() {\n                @Override\n                public void run() {\n                    synchronized (mSessions) {\n                        mSessions.remove(session.sessionId);\n                    }\n                }\n            });\n        }\n\n        public void onSessionPrepared(PackageInstallerSession session) {\n            // We prepared the destination to write into; we want to persist\n            // this, but it's not critical enough to block for.\n        }\n\n        public void onSessionSealedBlocking(PackageInstallerSession session) {\n            // It's very important that we block until we've recorded the\n            // session as being sealed, since we never want to allow mutation\n            // after sealing.\n        }\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/PackageParserEx.java",
    "content": "package com.lody.virtual.server.pm.parser;\n\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.InstrumentationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PackageParser;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.Signature;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.text.TextUtils;\n\nimport com.lody.virtual.client.core.VirtualCore;\nimport com.lody.virtual.client.env.Constants;\nimport com.lody.virtual.client.fixer.ComponentFixer;\nimport com.lody.virtual.helper.collection.ArrayMap;\nimport com.lody.virtual.helper.compat.BuildCompat;\nimport com.lody.virtual.helper.compat.PackageParserCompat;\nimport com.lody.virtual.helper.utils.FileUtils;\nimport com.lody.virtual.helper.utils.VLog;\nimport com.lody.virtual.os.VEnvironment;\nimport com.lody.virtual.server.pm.PackageSetting;\nimport com.lody.virtual.server.pm.PackageUserState;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport mirror.android.content.pm.ApplicationInfoL;\nimport mirror.android.content.pm.ApplicationInfoN;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserEx {\n\n    private static final String TAG = PackageParserEx.class.getSimpleName();\n\n    private static final ArrayMap<String, String[]> sSharedLibCache = new ArrayMap<>();\n\n    private static final String FAKE_SIG = \"308203553082023da0030201020204378edaaa300d06092a864886f70d01010b0500305a310d300b0603550406130466616b65310d300b0603550408130466616b65310d300b0603550407130466616b65310d300b060355040a130466616b65310d300b060355040b130466616b65310d300b0603550403130466616b653020170d3138303533303034343434385a180f32313237313230353034343434385a305a310d300b0603550406130466616b65310d300b0603550408130466616b65310d300b0603550407130466616b65310d300b060355040a130466616b65310d300b060355040b130466616b65310d300b0603550403130466616b6530820122300d06092a864886f70d01010105000382010f003082010a0282010100b766ff6afd8a53edd4cee4985bc90e0c515157b5e9f731818961f7250d0d1ac7c7fb80eb5aeb8c28478732e8ff38cff574bfa0eba8039f73af1532f939c4ef9684719efbaba2dd3c583a20907c1c55248a63098c6da23dcfc877763d5fe6061dddd399cf2f49e3250e23f9e687a4d182bcd0662179ba4c9983448e34b4c83e5abbf4f87e87add9157c75fd40de3416744507a3517915f35b6fcad78766e8e1879df8ab823a6ffa335e4790f6e29c87393732025b63ce3a38e42cb0d48cdceb902f191d7d45823db9a0678895e8bfc59b2af7526ca4c2dc3dbe7e70c7c840e666b9629d36e5ddf1d9a80c37f1ab1bc1fb30432914008fbde95d5d3db7853565510203010001a321301f301d0603551d0e04160414d8513e1ae21c64e9ebeee3507e24ea375eef958e300d06092a864886f70d01010b0500038201010088bf20b36428558359536dddcfff16fe233656a92364cb544d8acc43b0859f880a8da339dd430616085edf035e4e6e6dd2281ceb14adde2f05e9ac58d547a09083eece0c6d405289cb7918f85754ee545eefe35e30c103cad617905e94eb4fb68e6920a60d30577855f9feb6e3a664856f74aa9f824aa7d4a3adf85e162c67b9a4261e3185f038ead96112ae3e574d280425e90567352fb82bc9173302122025eaecfabd94d0f9be69a85c415f7cf7759c9651734300952027b316c37aaa1b2418865a3fc7b6bd1072c92ccaacdaa1cf9586d9b8310ceee066ce68859107dfc45ccce729ad9e75b53b584fa37dcd64da8673b1279c6c5861ed3792deac156c8a\";\n\n    public static VPackage parsePackage(File packageFile) throws Throwable {\n        PackageParser parser = PackageParserCompat.createParser(packageFile);\n        PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);\n        if (p.requestedPermissions.contains(\"android.permission.FAKE_PACKAGE_SIGNATURE\")\n                && p.mAppMetaData != null\n                && p.mAppMetaData.containsKey(\"fake-signature\")) {\n            String sig = p.mAppMetaData.getString(\"fake-signature\");\n            buildSignature(p, new Signature[]{new Signature(sig)});\n            VLog.d(TAG, \"Using fake-signature feature on : \" + p.packageName);\n        } else {\n            try {\n                PackageParserCompat.collectCertificates(parser, p, PackageParser.PARSE_IS_SYSTEM);\n            } catch (Throwable e) {\n                VLog.e(TAG, \"collectCertificates failed\", e);\n                if (VirtualCore.get().getContext().getFileStreamPath(Constants.FAKE_SIGNATURE_FLAG).exists()) {\n                    VLog.w(TAG, \"Using fake signature: \" + p.packageName);\n                    buildSignature(p, new Signature[]{new Signature(FAKE_SIG)});\n                } else {\n                    throw e;\n                }\n            }\n        }\n        return buildPackageCache(p);\n    }\n\n    private static void buildSignature(PackageParser.Package p, Signature[] signatures) {\n        if (Build.VERSION.SDK_INT < 28) {\n            p.mSignatures = signatures;\n        } else {\n            Object signingDetails = mirror.android.content.pm.PackageParser.Package.mSigningDetails.get(p);\n            mirror.android.content.pm.PackageParser.SigningDetails.pastSigningCertificates.set(signingDetails, signatures);\n            mirror.android.content.pm.PackageParser.SigningDetails.signatures.set(signingDetails, signatures);\n        }\n    }\n\n    public static VPackage readPackageCache(String packageName) {\n        Parcel p = Parcel.obtain();\n        try {\n            File cacheFile = VEnvironment.getPackageCacheFile(packageName);\n            FileInputStream is = new FileInputStream(cacheFile);\n            byte[] bytes = FileUtils.toByteArray(is);\n            is.close();\n            p.unmarshall(bytes, 0, bytes.length);\n            p.setDataPosition(0);\n            if (p.readInt() != 4) {\n                throw new IllegalStateException(\"Invalid version.\");\n            }\n            VPackage pkg = new VPackage(p);\n            addOwner(pkg);\n            return pkg;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n        return null;\n    }\n\n    public static void readSignature(VPackage pkg) {\n        File signatureFile = VEnvironment.getSignatureFile(pkg.packageName);\n        if (!signatureFile.exists()) {\n            return;\n        }\n        Parcel p = Parcel.obtain();\n        try {\n            FileInputStream fis = new FileInputStream(signatureFile);\n            byte[] bytes = FileUtils.toByteArray(fis);\n            fis.close();\n            p.unmarshall(bytes, 0, bytes.length);\n            p.setDataPosition(0);\n            pkg.mSignatures = p.createTypedArray(Signature.CREATOR);\n            if (BuildCompat.isPie()) {\n                pkg.signingInfo = p.readParcelable(Bundle.class.getClassLoader());\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n    }\n\n    public static void savePackageCache(VPackage pkg) {\n        final String packageName = pkg.packageName;\n        Parcel p = Parcel.obtain();\n        try {\n            p.writeInt(4);\n            pkg.writeToParcel(p, 0);\n            FileOutputStream fos = new FileOutputStream(VEnvironment.getPackageCacheFile(packageName));\n            fos.write(p.marshall());\n            fos.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            p.recycle();\n        }\n        Signature[] signatures = pkg.mSignatures;\n        if (signatures != null) {\n            File signatureFile = VEnvironment.getSignatureFile(packageName);\n            if (signatureFile.exists() && !signatureFile.delete()) {\n                VLog.w(TAG, \"Unable to delete the signatures of \" + packageName);\n            }\n            p = Parcel.obtain();\n            try {\n                p.writeTypedArray(signatures, 0);\n                if (BuildCompat.isPie()) {\n                    p.writeParcelable(pkg.signingInfo, 0);\n                }\n                FileUtils.writeParcelToFile(p, signatureFile);\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                p.recycle();\n            }\n        }\n    }\n\n    private static VPackage buildPackageCache(PackageParser.Package p) {\n        VPackage cache = new VPackage();\n        cache.activities = new ArrayList<>(p.activities.size());\n        cache.services = new ArrayList<>(p.services.size());\n        cache.receivers = new ArrayList<>(p.receivers.size());\n        cache.providers = new ArrayList<>(p.providers.size());\n        cache.instrumentation = new ArrayList<>(p.instrumentation.size());\n        cache.permissions = new ArrayList<>(p.permissions.size());\n        cache.permissionGroups = new ArrayList<>(p.permissionGroups.size());\n\n        for (PackageParser.Activity activity : p.activities) {\n            cache.activities.add(new VPackage.ActivityComponent(activity));\n        }\n        for (PackageParser.Service service : p.services) {\n            cache.services.add(new VPackage.ServiceComponent(service));\n        }\n        for (PackageParser.Activity receiver : p.receivers) {\n            cache.receivers.add(new VPackage.ActivityComponent(receiver));\n        }\n        for (PackageParser.Provider provider : p.providers) {\n            cache.providers.add(new VPackage.ProviderComponent(provider));\n        }\n        for (PackageParser.Instrumentation instrumentation : p.instrumentation) {\n            cache.instrumentation.add(new VPackage.InstrumentationComponent(instrumentation));\n        }\n        cache.requestedPermissions = new ArrayList<>(p.requestedPermissions.size());\n        cache.requestedPermissions.addAll(p.requestedPermissions);\n        if (mirror.android.content.pm.PackageParser.Package.protectedBroadcasts != null) {\n            List<String> protectedBroadcasts = mirror.android.content.pm.PackageParser.Package.protectedBroadcasts.get(p);\n            if (protectedBroadcasts != null) {\n                cache.protectedBroadcasts = new ArrayList<>(protectedBroadcasts);\n                cache.protectedBroadcasts.addAll(protectedBroadcasts);\n            }\n        }\n        cache.applicationInfo = p.applicationInfo;\n        if (Build.VERSION.SDK_INT < 28) {\n            cache.mSignatures = p.mSignatures;\n        } else {\n            Object signingDetails = mirror.android.content.pm.PackageParser.Package.mSigningDetails.get(p);\n            boolean hasPastSigningCertificates = mirror.android.content.pm.PackageParser.SigningDetails.hasPastSigningCertificates.call(signingDetails);\n            if (hasPastSigningCertificates) {\n                cache.mSignatures = new Signature[1];\n                cache.mSignatures[0] = mirror.android.content.pm.PackageParser.SigningDetails.pastSigningCertificates.get(signingDetails)[0];\n            } else {\n                boolean hasSignatures = mirror.android.content.pm.PackageParser.SigningDetails.hasSignatures.call(signingDetails);\n                if (hasSignatures) {\n                    Signature[] signatures = mirror.android.content.pm.PackageParser.SigningDetails.signatures.get(signingDetails);\n                    int numberOfSigs = signatures.length;\n                    cache.mSignatures = new Signature[numberOfSigs];\n                    System.arraycopy(signatures, 0, cache.mSignatures, 0, numberOfSigs);\n                }\n            }\n            cache.signingInfo = mirror.android.content.pm.PackageParser.SigningInfo.ctor.newInstance(signingDetails);\n        }\n        cache.mAppMetaData = p.mAppMetaData;\n        cache.packageName = p.packageName;\n        cache.mPreferredOrder = p.mPreferredOrder;\n        cache.mVersionName = p.mVersionName;\n        cache.mSharedUserId = p.mSharedUserId;\n        cache.mSharedUserLabel = p.mSharedUserLabel;\n        cache.usesLibraries = p.usesLibraries;\n        cache.mVersionCode = p.mVersionCode;\n        cache.mAppMetaData = p.mAppMetaData;\n        cache.configPreferences = p.configPreferences;\n        cache.reqFeatures = p.reqFeatures;\n\n        // for split apks\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            cache.splitNames = p.splitNames;\n            cache.codePath = p.codePath;\n            cache.baseCodePath = p.baseCodePath;\n            cache.splitCodePaths = p.splitCodePaths;\n        }\n\n        cache.usesOptionalLibraries = p.usesOptionalLibraries;\n\n        addOwner(cache);\n        return cache;\n    }\n\n    public static void initApplicationInfoBase(PackageSetting ps, VPackage p) {\n        ApplicationInfo ai = p.applicationInfo;\n        ai.flags |= ApplicationInfo.FLAG_HAS_CODE;\n        if (TextUtils.isEmpty(ai.processName)) {\n            ai.processName = ai.packageName;\n        }\n        ai.enabled = true;\n        ai.nativeLibraryDir = ps.libPath;\n        ai.uid = ps.appId;\n        ai.name = ComponentFixer.fixComponentClassName(ps.packageName, ai.name);\n        ai.publicSourceDir = ps.apkPath;\n        ai.sourceDir = ps.apkPath;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            ai.splitSourceDirs = ps.splitCodePaths;\n            ai.splitPublicSourceDirs = ps.splitCodePaths;\n\n            ApplicationInfoL.scanSourceDir.set(ai, ai.dataDir);\n            ApplicationInfoL.scanPublicSourceDir.set(ai, ai.dataDir);\n            String hostPrimaryCpuAbi = ApplicationInfoL.primaryCpuAbi.get(VirtualCore.get().getContext().getApplicationInfo());\n            ApplicationInfoL.primaryCpuAbi.set(ai, hostPrimaryCpuAbi);\n        }\n\n        if (ps.dependSystem) {\n            String[] sharedLibraryFiles = sSharedLibCache.get(ps.packageName);\n            if (sharedLibraryFiles == null) {\n                PackageManager hostPM = VirtualCore.get().getUnHookPackageManager();\n                try {\n                    ApplicationInfo hostInfo = hostPM.getApplicationInfo(ps.packageName, PackageManager.GET_SHARED_LIBRARY_FILES);\n                    sharedLibraryFiles = hostInfo.sharedLibraryFiles;\n                    if (sharedLibraryFiles == null) sharedLibraryFiles = new String[0];\n                    sSharedLibCache.put(ps.packageName, sharedLibraryFiles);\n                } catch (PackageManager.NameNotFoundException e) {\n                    e.printStackTrace();\n                }\n            }\n            ai.sharedLibraryFiles = sharedLibraryFiles;\n        }\n    }\n\n    private static void initApplicationAsUser(ApplicationInfo ai, int userId) {\n        ai.dataDir = VEnvironment.getDataUserPackageDirectory(userId, ai.packageName).getPath();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            ApplicationInfoL.scanSourceDir.set(ai, ai.dataDir);\n            ApplicationInfoL.scanPublicSourceDir.set(ai, ai.dataDir);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            if(Build.VERSION.SDK_INT < 26) {\n                ApplicationInfoN.deviceEncryptedDataDir.set(ai, ai.dataDir);\n                ApplicationInfoN.credentialEncryptedDataDir.set(ai, ai.dataDir);\n            }\n            ApplicationInfoN.deviceProtectedDataDir.set(ai, ai.dataDir);\n            ApplicationInfoN.credentialProtectedDataDir.set(ai, ai.dataDir);\n        }\n    }\n\n    private static void addOwner(VPackage p) {\n        for (VPackage.ActivityComponent activity : p.activities) {\n            activity.owner = p;\n            for (VPackage.ActivityIntentInfo info : activity.intents) {\n                info.activity = activity;\n            }\n        }\n        for (VPackage.ServiceComponent service : p.services) {\n            service.owner = p;\n            for (VPackage.ServiceIntentInfo info : service.intents) {\n                info.service = service;\n            }\n        }\n        for (VPackage.ActivityComponent receiver : p.receivers) {\n            receiver.owner = p;\n            for (VPackage.ActivityIntentInfo info : receiver.intents) {\n                info.activity = receiver;\n            }\n        }\n        for (VPackage.ProviderComponent provider : p.providers) {\n            provider.owner = p;\n            for (VPackage.ProviderIntentInfo info : provider.intents) {\n                info.provider = provider;\n            }\n        }\n        for (VPackage.InstrumentationComponent instrumentation : p.instrumentation) {\n            instrumentation.owner = p;\n        }\n        for (VPackage.PermissionComponent permission : p.permissions) {\n            permission.owner = p;\n        }\n        for (VPackage.PermissionGroupComponent group : p.permissionGroups) {\n            group.owner = p;\n        }\n    }\n\n    public static PackageInfo generatePackageInfo(VPackage p, int flags, long firstInstallTime, long lastUpdateTime, PackageUserState state, int userId) {\n        if (!checkUseInstalledOrHidden(state, flags)) {\n            return null;\n        }\n        if (p.mSignatures == null) {\n            readSignature(p);\n        }\n        PackageInfo pi = new PackageInfo();\n        pi.packageName = p.packageName;\n        pi.versionCode = p.mVersionCode;\n        pi.sharedUserLabel = p.mSharedUserLabel;\n        pi.versionName = p.mVersionName;\n        pi.sharedUserId = p.mSharedUserId;\n        pi.sharedUserLabel = p.mSharedUserLabel;\n        pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);\n        pi.firstInstallTime = firstInstallTime;\n        pi.lastUpdateTime = lastUpdateTime;\n        if (p.requestedPermissions != null && !p.requestedPermissions.isEmpty()) {\n            String[] requestedPermissions = new String[p.requestedPermissions.size()];\n            p.requestedPermissions.toArray(requestedPermissions);\n            pi.requestedPermissions = requestedPermissions;\n        }\n        if ((flags & PackageManager.GET_GIDS) != 0) {\n            pi.gids = PackageParserCompat.GIDS;\n        }\n        if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {\n            int N = p.configPreferences != null ? p.configPreferences.size() : 0;\n            if (N > 0) {\n                pi.configPreferences = new ConfigurationInfo[N];\n                p.configPreferences.toArray(pi.configPreferences);\n            }\n            N = p.reqFeatures != null ? p.reqFeatures.size() : 0;\n            if (N > 0) {\n                pi.reqFeatures = new FeatureInfo[N];\n                p.reqFeatures.toArray(pi.reqFeatures);\n            }\n        }\n        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {\n            final int N = p.activities.size();\n            if (N > 0) {\n                int num = 0;\n                final ActivityInfo[] res = new ActivityInfo[N];\n                for (int i = 0; i < N; i++) {\n                    final VPackage.ActivityComponent a = p.activities.get(i);\n                    res[num++] = generateActivityInfo(a, flags, state, userId);\n                }\n                pi.activities = res;\n            }\n        }\n        if ((flags & PackageManager.GET_RECEIVERS) != 0) {\n            final int N = p.receivers.size();\n            if (N > 0) {\n                int num = 0;\n                final ActivityInfo[] res = new ActivityInfo[N];\n                for (int i = 0; i < N; i++) {\n                    final VPackage.ActivityComponent a = p.receivers.get(i);\n                    res[num++] = generateActivityInfo(a, flags, state, userId);\n                }\n                pi.receivers = res;\n            }\n        }\n        if ((flags & PackageManager.GET_SERVICES) != 0) {\n            final int N = p.services.size();\n            if (N > 0) {\n                int num = 0;\n                final ServiceInfo[] res = new ServiceInfo[N];\n                for (int i = 0; i < N; i++) {\n                    final VPackage.ServiceComponent s = p.services.get(i);\n                    res[num++] = generateServiceInfo(s, flags, state, userId);\n                }\n                pi.services = res;\n            }\n        }\n        if ((flags & PackageManager.GET_PROVIDERS) != 0) {\n            final int N = p.providers.size();\n            if (N > 0) {\n                int num = 0;\n                final ProviderInfo[] res = new ProviderInfo[N];\n                for (int i = 0; i < N; i++) {\n                    final VPackage.ProviderComponent pr = p.providers.get(i);\n                    res[num++] = generateProviderInfo(pr, flags, state, userId);\n                }\n                pi.providers = res;\n            }\n        }\n        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {\n            int N = p.instrumentation.size();\n            if (N > 0) {\n                pi.instrumentation = new InstrumentationInfo[N];\n                for (int i = 0; i < N; i++) {\n                    pi.instrumentation[i] = generateInstrumentationInfo(\n                            p.instrumentation.get(i), flags);\n                }\n            }\n        }\n        boolean hasGetSignatureFlag = (flags & PackageManager.GET_SIGNATURES) != 0;\n        boolean hasGetSigningInfoFlag = BuildCompat.isPie() && (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0;\n\n        if (hasGetSignatureFlag || hasGetSigningInfoFlag) {\n            int N = (p.mSignatures != null) ? p.mSignatures.length : 0;\n            if (N > 0) {\n                pi.signatures = new Signature[N];\n                System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);\n            }\n        }\n        if (hasGetSigningInfoFlag) {\n            pi.signingInfo = p.signingInfo;\n        }\n        return pi;\n    }\n\n    private static boolean copyNeeded(int flags, VPackage p,\n                                      PackageUserState state, Bundle metaData, int userId) {\n        if (!state.installed || state.hidden) {\n            return true;\n        }\n        return (flags & PackageManager.GET_META_DATA) != 0\n                && (metaData != null || p.mAppMetaData != null);\n    }\n\n    public static ApplicationInfo generateApplicationInfo(VPackage p, int flags,\n                                                          PackageUserState state, int userId) {\n        if (p == null) return null;\n        if (!checkUseInstalledOrHidden(state, flags)) {\n            return null;\n        }\n\n        if (!copyNeeded(flags, p, state, null, userId)) {\n            initApplicationAsUser(p.applicationInfo, userId);\n            return p.applicationInfo;\n        }\n\n        // Make shallow copy so we can store the metadata/libraries safely\n        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);\n        if ((flags & PackageManager.GET_META_DATA) != 0) {\n            ai.metaData = p.mAppMetaData;\n        }\n        initApplicationAsUser(ai, userId);\n        return ai;\n    }\n\n\n    public static ActivityInfo generateActivityInfo(VPackage.ActivityComponent a, int flags,\n                                                    PackageUserState state, int userId) {\n        if (a == null) return null;\n        if (!checkUseInstalledOrHidden(state, flags)) {\n            return null;\n        }\n        // Make shallow copies so we can store the metadata safely\n        ActivityInfo ai = new ActivityInfo(a.info);\n        if ((flags & PackageManager.GET_META_DATA) != 0\n                && (a.metaData != null)) {\n            ai.metaData = a.metaData;\n        }\n        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);\n        return ai;\n    }\n\n    public static ServiceInfo generateServiceInfo(VPackage.ServiceComponent s, int flags,\n                                                  PackageUserState state, int userId) {\n        if (s == null) return null;\n        if (!checkUseInstalledOrHidden(state, flags)) {\n            return null;\n        }\n        ServiceInfo si = new ServiceInfo(s.info);\n        // Make shallow copies so we can store the metadata safely\n        if ((flags & PackageManager.GET_META_DATA) != 0 && s.metaData != null) {\n            si.metaData = s.metaData;\n        }\n        si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);\n        return si;\n    }\n\n    public static ProviderInfo generateProviderInfo(VPackage.ProviderComponent p, int flags,\n                                                    PackageUserState state, int userId) {\n        if (p == null) return null;\n        if (!checkUseInstalledOrHidden(state, flags)) {\n            return null;\n        }\n        // Make shallow copies so we can store the metadata safely\n        ProviderInfo pi = new ProviderInfo(p.info);\n        if ((flags & PackageManager.GET_META_DATA) != 0\n                && (p.metaData != null)) {\n            pi.metaData = p.metaData;\n        }\n\n        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {\n            pi.uriPermissionPatterns = null;\n        }\n        pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);\n        return pi;\n    }\n\n    public static InstrumentationInfo generateInstrumentationInfo(\n            VPackage.InstrumentationComponent i, int flags) {\n        if (i == null) return null;\n        if ((flags & PackageManager.GET_META_DATA) == 0) {\n            return i.info;\n        }\n        InstrumentationInfo ii = new InstrumentationInfo(i.info);\n        ii.metaData = i.metaData;\n        return ii;\n    }\n\n    public static PermissionInfo generatePermissionInfo(\n            VPackage.PermissionComponent p, int flags) {\n        if (p == null) return null;\n        if ((flags & PackageManager.GET_META_DATA) == 0) {\n            return p.info;\n        }\n        PermissionInfo pi = new PermissionInfo(p.info);\n        pi.metaData = p.metaData;\n        return pi;\n    }\n\n    public static PermissionGroupInfo generatePermissionGroupInfo(\n            VPackage.PermissionGroupComponent pg, int flags) {\n        if (pg == null) return null;\n        if ((flags & PackageManager.GET_META_DATA) == 0) {\n            return pg.info;\n        }\n        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);\n        pgi.metaData = pg.metaData;\n        return pgi;\n    }\n\n    private static boolean checkUseInstalledOrHidden(PackageUserState state, int flags) {\n        //noinspection deprecation\n        return (state.installed && !state.hidden)\n                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/VPackage.java",
    "content": "package com.lody.virtual.server.pm.parser;\n\nimport android.Manifest;\nimport android.content.ComponentName;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.InstrumentationInfo;\nimport android.content.pm.PackageParser;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.Signature;\nimport android.content.pm.SigningInfo;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.lody.virtual.helper.compat.BuildCompat;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * @author Lody\n */\n\npublic class VPackage implements Parcelable {\n\n    public static final Creator<VPackage> CREATOR = new Creator<VPackage>() {\n        @Override\n        public VPackage createFromParcel(Parcel source) {\n            return new VPackage(source);\n        }\n\n        @Override\n        public VPackage[] newArray(int size) {\n            return new VPackage[size];\n        }\n    };\n    public ArrayList<ActivityComponent> activities;\n    public ArrayList<ActivityComponent> receivers;\n    public ArrayList<ProviderComponent> providers;\n    public ArrayList<ServiceComponent> services;\n    public ArrayList<InstrumentationComponent> instrumentation;\n    public ArrayList<PermissionComponent> permissions;\n    public ArrayList<PermissionGroupComponent> permissionGroups;\n    public ArrayList<String> requestedPermissions;\n    public ArrayList<String> protectedBroadcasts;\n    public ApplicationInfo applicationInfo;\n    public Signature[] mSignatures;\n    public Bundle mAppMetaData;\n    public String packageName;\n    public int mPreferredOrder;\n    public String mVersionName;\n    public String mSharedUserId;\n    public ArrayList<String> usesLibraries;\n    public int mVersionCode;\n    public int mSharedUserLabel;\n    // Applications hardware preferences\n    public ArrayList<ConfigurationInfo> configPreferences = null;\n    // Applications requested features\n    public ArrayList<FeatureInfo> reqFeatures = null;\n    public Object mExtras;\n\n    public String[] splitNames;\n    public ArrayList<String> usesOptionalLibraries;\n\n    /**\n     * Path where this package was found on disk. For monolithic packages\n     * this is path to single base APK file; for cluster packages this is\n     * path to the cluster directory.\n     */\n    public String codePath;\n\n    /** Path of base APK */\n    public String baseCodePath;\n    /** Paths of any split APKs, ordered by parsed splitName */\n    public String[] splitCodePaths;\n\n    public SigningInfo signingInfo;\n\n    public VPackage() {\n    }\n\n    protected VPackage(Parcel in) {\n        int N = in.readInt();\n        this.activities = new ArrayList<>(N);\n        while (N-- > 0) {\n            activities.add(new ActivityComponent(in));\n        }\n        N = in.readInt();\n        this.receivers = new ArrayList<>(N);\n        while (N-- > 0) {\n            receivers.add(new ActivityComponent(in));\n        }\n        N = in.readInt();\n        this.providers = new ArrayList<>(N);\n        while (N-- > 0) {\n            providers.add(new ProviderComponent(in));\n        }\n        N = in.readInt();\n        this.services = new ArrayList<>(N);\n        while (N-- > 0) {\n            services.add(new ServiceComponent(in));\n        }\n        N = in.readInt();\n        this.instrumentation = new ArrayList<>(N);\n        while (N-- > 0) {\n            instrumentation.add(new InstrumentationComponent(in));\n        }\n        N = in.readInt();\n        this.permissions = new ArrayList<>(N);\n        while (N-- > 0) {\n            permissions.add(new PermissionComponent(in));\n        }\n        N = in.readInt();\n        this.permissionGroups = new ArrayList<>(N);\n        while (N-- > 0) {\n            permissionGroups.add(new PermissionGroupComponent(in));\n        }\n        this.requestedPermissions = in.createStringArrayList();\n        this.protectedBroadcasts = in.createStringArrayList();\n        this.applicationInfo = in.readParcelable(ApplicationInfo.class.getClassLoader());\n        this.mAppMetaData = in.readBundle(Bundle.class.getClassLoader());\n        this.packageName = in.readString();\n        this.mPreferredOrder = in.readInt();\n        this.mVersionName = in.readString();\n        this.mSharedUserId = in.readString();\n        this.usesLibraries = in.createStringArrayList();\n        this.mVersionCode = in.readInt();\n        this.mSharedUserLabel = in.readInt();\n        this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR);\n        this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR);\n\n        this.splitNames = in.createStringArray();\n        this.codePath = in.readString();\n        this.baseCodePath = in.readString();\n        this.splitCodePaths = in.createStringArray();\n\n        this.usesOptionalLibraries = in.createStringArrayList();\n\n        if (BuildCompat.isPie()) {\n            this.signingInfo = in.readParcelable(Bundle.class.getClassLoader());\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.activities.size());\n        for (ActivityComponent component : activities) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (ActivityIntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.receivers.size());\n        for (ActivityComponent component : receivers) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (ActivityIntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.providers.size());\n        for (ProviderComponent component : providers) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (ProviderIntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.services.size());\n        for (ServiceComponent component : services) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (ServiceIntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.instrumentation.size());\n        for (InstrumentationComponent component : instrumentation) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (IntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.permissions.size());\n        for (PermissionComponent component : permissions) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (IntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeInt(this.permissionGroups.size());\n        for (PermissionGroupComponent component : permissionGroups) {\n            dest.writeParcelable(component.info, 0);\n            dest.writeString(component.className);\n            dest.writeBundle(component.metaData);\n            dest.writeInt(component.intents != null ? component.intents.size() : 0);\n            if (component.intents != null) {\n                for (IntentInfo info : component.intents) {\n                    info.writeToParcel(dest, flags);\n                }\n            }\n        }\n        dest.writeStringList(this.requestedPermissions);\n        dest.writeStringList(this.protectedBroadcasts);\n        dest.writeParcelable(this.applicationInfo, flags);\n        dest.writeBundle(this.mAppMetaData);\n        dest.writeString(this.packageName);\n        dest.writeInt(this.mPreferredOrder);\n        dest.writeString(this.mVersionName);\n        dest.writeString(this.mSharedUserId);\n        dest.writeStringList(this.usesLibraries);\n        dest.writeInt(this.mVersionCode);\n        dest.writeInt(this.mSharedUserLabel);\n        dest.writeTypedList(this.configPreferences);\n        dest.writeTypedList(this.reqFeatures);\n\n        dest.writeStringArray(this.splitNames);\n        dest.writeString(this.codePath);\n        dest.writeString(this.baseCodePath);\n        dest.writeStringArray(this.splitCodePaths);\n\n        dest.writeStringList(this.usesOptionalLibraries);\n\n        if (BuildCompat.isPie()) {\n            dest.writeParcelable(this.signingInfo, flags);\n        }\n    }\n\n    public static class ActivityIntentInfo extends IntentInfo {\n\n        public ActivityComponent activity;\n\n        public ActivityIntentInfo(PackageParser.IntentInfo info) {\n            super(info);\n        }\n\n        protected ActivityIntentInfo(Parcel in) {\n            super(in);\n        }\n    }\n\n    public static class ServiceIntentInfo extends IntentInfo {\n        public ServiceComponent service;\n\n        public ServiceIntentInfo(PackageParser.IntentInfo info) {\n            super(info);\n        }\n\n        protected ServiceIntentInfo(Parcel in) {\n            super(in);\n        }\n    }\n\n    public static class ProviderIntentInfo extends IntentInfo {\n        public ProviderComponent provider;\n\n        public ProviderIntentInfo(PackageParser.IntentInfo info) {\n            super(info);\n        }\n\n        protected ProviderIntentInfo(Parcel in) {\n            super(in);\n        }\n    }\n\n    public static class IntentInfo implements Parcelable {\n        public static final Creator<IntentInfo> CREATOR = new Creator<IntentInfo>() {\n            @Override\n            public IntentInfo createFromParcel(Parcel source) {\n                return new IntentInfo(source);\n            }\n\n            @Override\n            public IntentInfo[] newArray(int size) {\n                return new IntentInfo[size];\n            }\n        };\n        public IntentFilter filter;\n        public boolean hasDefault;\n        public int labelRes;\n        public String nonLocalizedLabel;\n        public int icon;\n        public int logo;\n        public int banner;\n\n        public IntentInfo(PackageParser.IntentInfo info) {\n            this.filter = info;\n            this.hasDefault = info.hasDefault;\n            this.labelRes = info.labelRes;\n            if (info.nonLocalizedLabel != null) {\n                this.nonLocalizedLabel = info.nonLocalizedLabel.toString();\n            }\n            this.icon = info.icon;\n            this.logo = info.logo;\n            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {\n                this.banner = info.banner;\n            }\n\n        }\n\n        protected IntentInfo(Parcel in) {\n            this.filter = in.readParcelable(VPackage.class.getClassLoader());\n            this.hasDefault = in.readByte() != 0;\n            this.labelRes = in.readInt();\n            this.nonLocalizedLabel = in.readString();\n            this.icon = in.readInt();\n            this.logo = in.readInt();\n            this.banner = in.readInt();\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeParcelable(this.filter, flags);\n            dest.writeByte(this.hasDefault ? (byte) 1 : (byte) 0);\n            dest.writeInt(this.labelRes);\n            dest.writeString(this.nonLocalizedLabel);\n            dest.writeInt(this.icon);\n            dest.writeInt(this.logo);\n            dest.writeInt(this.banner);\n        }\n    }\n\n    public static class Component<II extends IntentInfo> {\n        public VPackage owner;\n        public ArrayList<II> intents;\n        public String className;\n        public Bundle metaData;\n        private ComponentName componentName;\n\n        protected Component() {\n\n        }\n\n        public Component(PackageParser.Component component) {\n            this.className = component.className;\n            this.metaData = component.metaData;\n        }\n\n        public ComponentName getComponentName() {\n            if (componentName != null) {\n                return componentName;\n            }\n            if (className != null) {\n                componentName = new ComponentName(owner.packageName,\n                        className);\n            }\n            return componentName;\n        }\n\n    }\n\n    public static class ActivityComponent extends Component<ActivityIntentInfo> {\n        public ActivityInfo info;\n\n        public ActivityComponent(PackageParser.Activity activity) {\n            super(activity);\n            if (activity.intents != null) {\n                this.intents = new ArrayList<>(activity.intents.size());\n                for (Object o : activity.intents) {\n                    intents.add(new ActivityIntentInfo((PackageParser.IntentInfo) o));\n                }\n            }\n            info = activity.info;\n        }\n\n        protected ActivityComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new ActivityIntentInfo(src));\n            }\n        }\n    }\n\n    public static class ServiceComponent extends Component<ServiceIntentInfo> {\n        public ServiceInfo info;\n\n        public ServiceComponent(PackageParser.Service service) {\n            super(service);\n            if (service.intents != null) {\n                this.intents = new ArrayList<>(service.intents.size());\n                for (Object o : service.intents) {\n                    intents.add(new ServiceIntentInfo((PackageParser.IntentInfo) o));\n                }\n            }\n            this.info = service.info;\n        }\n\n        protected ServiceComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new ServiceIntentInfo(src));\n            }\n        }\n    }\n\n    public static class ProviderComponent extends Component<ProviderIntentInfo> {\n        public ProviderInfo info;\n\n        public ProviderComponent(PackageParser.Provider provider) {\n            super(provider);\n            if (provider.intents != null) {\n                this.intents = new ArrayList<>(provider.intents.size());\n                for (Object o : provider.intents) {\n                    intents.add(new ProviderIntentInfo((PackageParser.IntentInfo) o));\n                }\n            }\n            this.info = provider.info;\n        }\n\n        protected ProviderComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new ProviderIntentInfo(src));\n            }\n        }\n    }\n\n    public static class InstrumentationComponent extends Component<IntentInfo> {\n        public InstrumentationInfo info;\n\n        public InstrumentationComponent(PackageParser.Instrumentation i) {\n            super(i);\n            this.info = i.info;\n        }\n\n        protected InstrumentationComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new IntentInfo(src));\n            }\n        }\n    }\n\n    public static class PermissionComponent extends Component<IntentInfo> {\n\n        // https://developer.android.com/guide/topics/security/permissions?hl=zh-cn\n        public static Set<String> DANGEROUS_PERMISSION = new HashSet<String>() {{\n            // CALENDAR group\n            add(Manifest.permission.READ_CALENDAR);\n            add(Manifest.permission.WRITE_CALENDAR);\n\n            // CAMERA\n            add(Manifest.permission.CAMERA);\n\n            // CONTACTS\n            add(Manifest.permission.READ_CONTACTS);\n            add(Manifest.permission.WRITE_CONTACTS);\n            add(Manifest.permission.GET_ACCOUNTS);\n\n            // LOCATION\n            add(Manifest.permission.ACCESS_FINE_LOCATION);\n            add(Manifest.permission.ACCESS_COARSE_LOCATION);\n\n            // PHONE\n            add(Manifest.permission.READ_PHONE_STATE);\n            add(Manifest.permission.CALL_PHONE);\n            add(Manifest.permission.READ_CALL_LOG);\n            add(Manifest.permission.WRITE_CALL_LOG);\n            add(Manifest.permission.ADD_VOICEMAIL);\n            add(Manifest.permission.USE_SIP);\n            add(Manifest.permission.PROCESS_OUTGOING_CALLS);\n\n            // SENSORS\n            add(Manifest.permission.BODY_SENSORS);\n\n            // SMS\n            add(Manifest.permission.SEND_SMS);\n            add(Manifest.permission.RECEIVE_SMS);\n            add(Manifest.permission.READ_SMS);\n            add(Manifest.permission.RECEIVE_WAP_PUSH);\n            add(Manifest.permission.RECEIVE_MMS);\n\n            // STORAGE\n            add(Manifest.permission.READ_EXTERNAL_STORAGE);\n            add(Manifest.permission.WRITE_EXTERNAL_STORAGE);\n        }};\n\n        public PermissionInfo info;\n\n        public PermissionComponent(PackageParser.Permission p) {\n            super(p);\n            this.info = p.info;\n        }\n\n        protected PermissionComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new IntentInfo(src));\n            }\n        }\n    }\n\n    public static class PermissionGroupComponent extends Component<IntentInfo> {\n        public PermissionGroupInfo info;\n\n\n        public PermissionGroupComponent(PackageParser.PermissionGroup p) {\n            super(p);\n            this.info = p.info;\n        }\n\n        protected PermissionGroupComponent(Parcel src) {\n            info = src.readParcelable(ActivityInfo.class.getClassLoader());\n            className = src.readString();\n            metaData = src.readBundle(Bundle.class.getClassLoader());\n            int N = src.readInt();\n            intents = new ArrayList<>(N);\n            while (N-- > 0) {\n                intents.add(new IntentInfo(src));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/secondary/BinderDelegateService.java",
    "content": "package com.lody.virtual.server.secondary;\n\nimport android.content.ComponentName;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.lody.virtual.server.IBinderDelegateService;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\npublic class BinderDelegateService extends IBinderDelegateService.Stub {\n\n    private ComponentName name;\n    private IBinder service;\n\n    private interface ProxyBinderFactory {\n        IBinder create(Binder binder);\n    }\n    private static final Map<String, ProxyBinderFactory> mFactories = new HashMap<>();\n    static {\n        mFactories.put(\"android.accounts.IAccountAuthenticator\", new ProxyBinderFactory() {\n            @Override\n            public IBinder create(Binder binder) {\n                return new FakeIdentityBinder(binder);\n            }\n        });\n    }\n\n    public BinderDelegateService(ComponentName name, IBinder service) {\n        this.name = name;\n        if (service instanceof Binder) {\n            Binder localService = (Binder) service;\n            ProxyBinderFactory factory = mFactories.get(localService.getInterfaceDescriptor());\n            if (factory != null) {\n                service = factory.create(localService);\n            }\n        }\n        this.service = service;\n    }\n\n    @Override\n    public ComponentName getComponent() throws RemoteException {\n        return name;\n    }\n\n    @Override\n    public IBinder getService() throws RemoteException {\n        return service;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/secondary/FakeIdentityBinder.java",
    "content": "package com.lody.virtual.server.secondary;\n\nimport android.os.Binder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.Process;\nimport android.os.RemoteException;\n\n/**\n * @author Lody\n */\npublic class FakeIdentityBinder extends Binder {\n\n    private Binder mBase;\n\n    public FakeIdentityBinder(Binder binder) {\n        this.mBase = binder;\n    }\n\n    public final void attachInterface(IInterface owner, String descriptor) {\n        mBase.attachInterface(owner, descriptor);\n    }\n\n    public final String getInterfaceDescriptor() {\n        return mBase.getInterfaceDescriptor();\n    }\n\n    public final boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {\n        long clearCallingIdentity = Binder.clearCallingIdentity();\n        try {\n            Binder.restoreCallingIdentity(getFakeIdentity());\n            return mBase.transact(code, data, reply, flags);\n        } finally {\n            Binder.restoreCallingIdentity(clearCallingIdentity);\n        }\n    }\n\n    /**\n     * See: http://androidxref.com/6.0.1_r10/xref/frameworks/native/libs/binder/IPCThreadState.cpp#356\n     */\n    protected long getFakeIdentity() {\n        return (long) getFakeUid() << 32 | (long) getFakePid();\n    }\n\n    protected int getFakeUid() {\n        return Process.myUid();\n    }\n\n    protected int getFakePid() {\n        return Process.myPid();\n    }\n\n    public final IInterface queryLocalInterface(String descriptor) {\n        return mBase.queryLocalInterface(descriptor);\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VSConfig.java",
    "content": "package com.lody.virtual.server.vs;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * @author Lody\n *\n * Config of virtual storage.\n *\n */\npublic class VSConfig implements Parcelable {\n\n    public boolean enable;\n\n    public String vsPath;\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeByte(this.enable ? (byte) 1 : (byte) 0);\n        dest.writeString(this.vsPath);\n    }\n\n    public VSConfig() {\n    }\n\n    protected VSConfig(Parcel in) {\n        this.enable = in.readByte() != 0;\n        this.vsPath = in.readString();\n    }\n\n    public static final Parcelable.Creator<VSConfig> CREATOR = new Parcelable.Creator<VSConfig>() {\n        @Override\n        public VSConfig createFromParcel(Parcel source) {\n            return new VSConfig(source);\n        }\n\n        @Override\n        public VSConfig[] newArray(int size) {\n            return new VSConfig[size];\n        }\n    };\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VSPersistenceLayer.java",
    "content": "package com.lody.virtual.server.vs;\n\nimport android.os.Parcel;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.helper.PersistenceLayer;\nimport com.lody.virtual.os.VEnvironment;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author Lody\n */\n\nclass VSPersistenceLayer extends PersistenceLayer {\n\n    private static final char[] MAGIC = {'v', 's', 'a'};\n    private static final int CURRENT_VERSION = 1;\n    private final VirtualStorageService mService;\n\n    VSPersistenceLayer(VirtualStorageService service) {\n        super(VEnvironment.getVSConfigFile());\n        this.mService = service;\n    }\n\n    @Override\n    public int getCurrentVersion() {\n        return CURRENT_VERSION;\n    }\n\n    @Override\n    public void writeMagic(Parcel p) {\n        p.writeCharArray(MAGIC);\n    }\n\n    @Override\n    public boolean verifyMagic(Parcel p) {\n        char[] magic = p.createCharArray();\n        return Arrays.equals(magic, MAGIC);\n    }\n\n\n    @Override\n    public void writePersistenceData(Parcel p) {\n        final SparseArray<HashMap<String, VSConfig>> configs = mService.getConfigs();\n        int N = configs.size();\n        p.writeInt(N);\n        while (N-- > 0) {\n            int userId = configs.keyAt(N);\n            Map<String, VSConfig> userMap = configs.valueAt(N);\n            p.writeInt(userId);\n            p.writeMap(userMap);\n        }\n\n    }\n\n    @Override\n    public void readPersistenceData(Parcel p) {\n        final SparseArray<HashMap<String, VSConfig>> configs = mService.getConfigs();\n        int N = p.readInt();\n        while (N-- > 0) {\n            int userId = p.readInt();\n            //noinspection unchecked\n            HashMap<String, VSConfig> userMap = p.readHashMap(VSConfig.class.getClassLoader());\n            configs.put(userId, userMap);\n        }\n    }\n\n    @Override\n    public boolean onVersionConflict(int fileVersion, int currentVersion) {\n        return false;\n    }\n\n\n    @Override\n    public void onPersistenceFileDamage() {\n\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/com/lody/virtual/server/vs/VirtualStorageService.java",
    "content": "package com.lody.virtual.server.vs;\n\nimport android.os.RemoteException;\nimport android.util.SparseArray;\n\nimport com.lody.virtual.server.IVirtualStorageService;\nimport com.lody.virtual.server.pm.VUserManagerService;\n\nimport java.util.HashMap;\n\n/**\n * @author Lody\n */\n\npublic class VirtualStorageService extends IVirtualStorageService.Stub {\n\n    private static final VirtualStorageService sService = new VirtualStorageService();\n    private final VSPersistenceLayer mLayer = new VSPersistenceLayer(this);\n    private final SparseArray<HashMap<String, VSConfig>> mConfigs = new SparseArray<>();\n\n    public static VirtualStorageService get() {\n        return sService;\n    }\n\n    private VirtualStorageService() {\n        mLayer.read();\n    }\n\n    SparseArray<HashMap<String, VSConfig>> getConfigs() {\n        return mConfigs;\n    }\n\n    @Override\n    public void setVirtualStorage(String packageName, int userId, String vsPath) throws RemoteException {\n        checkUserId(userId);\n        synchronized (mConfigs) {\n            VSConfig config = getOrCreateVSConfigLocked(packageName, userId);\n            config.vsPath = vsPath;\n            mLayer.save();\n        }\n    }\n\n    private VSConfig getOrCreateVSConfigLocked(String packageName, int userId) {\n        HashMap<String, VSConfig> userMap = mConfigs.get(userId);\n        if (userMap == null) {\n            userMap = new HashMap<>();\n            mConfigs.put(userId, userMap);\n        }\n        VSConfig config = userMap.get(packageName);\n        if (config == null) {\n            config = new VSConfig();\n            config.enable = false;\n            userMap.put(packageName, config);\n        }\n        return config;\n    }\n\n\n    @Override\n    public String getVirtualStorage(String packageName, int userId) throws RemoteException {\n        checkUserId(userId);\n        synchronized (mConfigs) {\n            VSConfig config = getOrCreateVSConfigLocked(packageName, userId);\n            return config.vsPath;\n        }\n    }\n\n    @Override\n    public void setVirtualStorageState(String packageName, int userId, boolean enable) throws RemoteException {\n        checkUserId(userId);\n        synchronized (mConfigs) {\n            VSConfig config = getOrCreateVSConfigLocked(packageName, userId);\n            config.enable = enable;\n            mLayer.save();\n        }\n\n    }\n\n    @Override\n    public boolean isVirtualStorageEnable(String packageName, int userId) throws RemoteException {\n        checkUserId(userId);\n        synchronized (mConfigs) {\n            VSConfig config = getOrCreateVSConfigLocked(packageName, userId);\n            return config.enable;\n        }\n\n    }\n\n    private void checkUserId(int userId) {\n        if (!VUserManagerService.get().exists(userId)) {\n            throw new IllegalStateException(\"Invalid userId \" + userId);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/MethodParams.java",
    "content": "package mirror;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MethodParams {\n    Class<?>[] value();\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/MethodReflectParams.java",
    "content": "package mirror;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MethodReflectParams {\n    String[] value();\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefBoolean.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefBoolean {\n    private Field field;\n\n    public RefBoolean(Class<?> cls, Field field) throws NoSuchFieldException {\n            this.field = cls.getDeclaredField(field.getName());\n            this.field.setAccessible(true);\n    }\n\n    public boolean get(Object object) {\n        try {\n            return this.field.getBoolean(object);\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    public void set(Object obj, boolean value) {\n        try {\n            this.field.setBoolean(obj, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefClass.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.HashMap;\n\npublic final class RefClass {\n\n    private static HashMap<Class<?>,Constructor<?>> REF_TYPES = new HashMap<Class<?>, Constructor<?>>();\n    static {\n        try {\n            REF_TYPES.put(RefObject.class, RefObject.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefMethod.class, RefMethod.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefInt.class, RefInt.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefLong.class, RefLong.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefFloat.class, RefFloat.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefDouble.class, RefDouble.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefBoolean.class, RefBoolean.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefStaticObject.class, RefStaticObject.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefStaticInt.class, RefStaticInt.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefStaticMethod.class, RefStaticMethod.class.getConstructor(Class.class, Field.class));\n            REF_TYPES.put(RefConstructor.class, RefConstructor.class.getConstructor(Class.class, Field.class));\n        }\n        catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static Class<?> load(Class<?> mappingClass, String className) {\n        try {\n            return load(mappingClass, Class.forName(className));\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n\n    public static Class load(Class mappingClass, Class<?> realClass) {\n        Field[] fields = mappingClass.getDeclaredFields();\n        for (Field field : fields) {\n            try {\n                if (Modifier.isStatic(field.getModifiers())) {\n                    Constructor<?> constructor = REF_TYPES.get(field.getType());\n                    if (constructor != null) {\n                        field.set(null, constructor.newInstance(realClass, field));\n                    }\n                }\n            }\n            catch (Exception e) {\n                // Ignore\n            }\n        }\n        return realClass;\n    }\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefConstructor.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\n\npublic class RefConstructor<T> {\n    private Constructor<?> ctor;\n\n    public RefConstructor(Class<?> cls, Field field) throws NoSuchMethodException {\n        if (field.isAnnotationPresent(MethodParams.class)) {\n            Class<?>[] types = field.getAnnotation(MethodParams.class).value();\n            ctor = cls.getDeclaredConstructor(types);\n        } else if (field.isAnnotationPresent(MethodReflectParams.class)) {\n            String[] values = field.getAnnotation(MethodReflectParams.class).value();\n            Class[] parameterTypes = new Class[values.length];\n            int N = 0;\n            while (N < values.length) {\n                try {\n                    parameterTypes[N] = Class.forName(values[N]);\n                    N++;\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            ctor = cls.getDeclaredConstructor(parameterTypes);\n        } else {\n            ctor = cls.getDeclaredConstructor();\n        }\n        if (ctor != null && !ctor.isAccessible()) {\n            ctor.setAccessible(true);\n        }\n    }\n\n    public T newInstance() {\n        try {\n            return (T) ctor.newInstance();\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public T newInstance(Object... params) {\n        try {\n            return (T) ctor.newInstance(params);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefDouble.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefDouble {\n    private Field field;\n\n    public RefDouble(Class cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public double get(Object object) {\n        try {\n            return this.field.getDouble(object);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public void set(Object obj, double value) {\n        try {\n            this.field.setDouble(obj, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefFloat.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefFloat {\n    private Field field;\n\n    public RefFloat(Class cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public float get(Object object) {\n        try {\n            return this.field.getFloat(object);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public void set(Object obj, float value) {\n        try {\n            this.field.setFloat(obj, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefInt.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefInt {\n    private Field field;\n\n    public RefInt(Class cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public int get(Object object) {\n        try {\n            return this.field.getInt(object);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public void set(Object obj, int intValue) {\n        try {\n            this.field.setInt(obj, intValue);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefLong.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefLong {\n    private Field field;\n\n    public RefLong(Class cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public long get(Object object) {\n        try {\n            return this.field.getLong(object);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public void set(Object obj, long value) {\n        try {\n            this.field.setLong(obj, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefMethod.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport static mirror.RefStaticMethod.getProtoType;\n\n@SuppressWarnings(\"unchecked\")\npublic class RefMethod<T> {\n    private Method method;\n\n    public RefMethod(Class<?> cls, Field field) throws NoSuchMethodException {\n        if (field.isAnnotationPresent(MethodParams.class)) {\n            Class<?>[] types = field.getAnnotation(MethodParams.class).value();\n            for (int i = 0; i < types.length; i++) {\n                Class<?> clazz = types[i];\n                if (clazz.getClassLoader() == getClass().getClassLoader()) {\n                    try {\n                        Class.forName(clazz.getName());\n                        Class<?> realClass = (Class<?>) clazz.getField(\"TYPE\").get(null);\n                        types[i] = realClass;\n                    } catch (Throwable e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            }\n            this.method = cls.getDeclaredMethod(field.getName(), types);\n            this.method.setAccessible(true);\n        } else if (field.isAnnotationPresent(MethodReflectParams.class)) {\n            String[] typeNames = field.getAnnotation(MethodReflectParams.class).value();\n            Class<?>[] types = new Class<?>[typeNames.length];\n            for (int i = 0; i < typeNames.length; i++) {\n                Class<?> type = getProtoType(typeNames[i]);\n                if (type == null) {\n                    try {\n                        type = Class.forName(typeNames[i]);\n                    } catch (ClassNotFoundException e) {\n                        e.printStackTrace();\n                    }\n                }\n                types[i] = type;\n            }\n            this.method = cls.getDeclaredMethod(field.getName(), types);\n            this.method.setAccessible(true);\n        }\n        else {\n            for (Method method : cls.getDeclaredMethods()) {\n                if (method.getName().equals(field.getName())) {\n                    this.method = method;\n                    this.method.setAccessible(true);\n                    break;\n                }\n            }\n        }\n        if (this.method == null) {\n            throw new NoSuchMethodException(field.getName());\n        }\n    }\n\n    public T call(Object receiver, Object... args) {\n        try {\n            return (T) this.method.invoke(receiver, args);\n        } catch (InvocationTargetException e) {\n            if (e.getCause() != null) {\n                e.getCause().printStackTrace();\n            } else {\n                e.printStackTrace();\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public T callWithException(Object receiver, Object... args) throws Throwable {\n        try {\n            return (T) this.method.invoke(receiver, args);\n        } catch (InvocationTargetException e) {\n            if (e.getCause() != null) {\n                throw e.getCause();\n            }\n            throw e;\n        }\n    }\n\n    public Class<?>[] paramList() {\n        return method.getParameterTypes();\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefObject.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\n@SuppressWarnings(\"unchecked\")\npublic class RefObject<T> {\n    private Field field;\n\n    public RefObject(Class<?> cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public T get(Object object) {\n        try {\n            return (T) this.field.get(object);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public void set(Object obj, T value) {\n        try {\n            this.field.set(obj, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefStaticInt.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\npublic class RefStaticInt {\n    private Field field;\n\n    public RefStaticInt(Class<?> cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public int get() {\n        try {\n            return this.field.getInt(null);\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n\n    public void set(int value) {\n        try {\n            this.field.setInt(null, value);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefStaticMethod.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\n@SuppressWarnings(\"unchecked\")\npublic class RefStaticMethod<T> {\n    private Method method;\n\n    public RefStaticMethod(Class<?> cls, Field field) throws NoSuchMethodException {\n        if (field.isAnnotationPresent(MethodParams.class)) {\n            Class<?>[] types = field.getAnnotation(MethodParams.class).value();\n            for (int i = 0; i < types.length; i++) {\n                Class<?> clazz = types[i];\n                if (clazz.getClassLoader() == getClass().getClassLoader()) {\n                    try {\n                        Class.forName(clazz.getName());\n                        Class<?> realClass = (Class<?>) clazz.getField(\"TYPE\").get(null);\n                        types[i] = realClass;\n                    } catch (Throwable e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            }\n            this.method = cls.getDeclaredMethod(field.getName(), types);\n            this.method.setAccessible(true);\n        } else if (field.isAnnotationPresent(MethodReflectParams.class)) {\n            boolean arrayset=false;\n            String[] typeNames = field.getAnnotation(MethodReflectParams.class).value();\n            Class<?>[] types = new Class<?>[typeNames.length];\n            Class<?>[] types2 = new Class<?>[typeNames.length];\n            for (int i = 0; i < typeNames.length; i++) {\n                Class<?> type = getProtoType(typeNames[i]);\n                if (type == null) {\n                    try {\n                        type = Class.forName(typeNames[i]);\n                    } catch (ClassNotFoundException e) {\n                        e.printStackTrace();\n                    }\n                }\n                types[i] = type;\n                if(\"java.util.HashSet\".equals(typeNames[i])){\n                    arrayset=true;\n                    Class<?> type2 =type;\n                    try {\n                        type2 = Class.forName(\"android.util.ArraySet\");\n                    } catch (ClassNotFoundException e) {\n                        e.printStackTrace();\n                    }\n                    if(type2 != null) {\n                        types2[i] = type2;\n                    }else{\n                        types2[i] = type;\n                    }\n                }else{\n                    types2[i] = type;\n                }\n            }\n            try {\n                this.method = cls.getDeclaredMethod(field.getName(), types);\n            }catch (Exception e){\n                e.printStackTrace();\n                if(arrayset){\n                    this.method = cls.getDeclaredMethod(field.getName(), types2);\n                }\n            }\n            this.method.setAccessible(true);\n        } else {\n            for (Method method : cls.getDeclaredMethods()) {\n                if (method.getName().equals(field.getName())) {\n                    this.method = method;\n                    this.method.setAccessible(true);\n                    break;\n                }\n            }\n        }\n\n        if (this.method == null) {\n            throw new NoSuchMethodException(field.getName());\n        }\n    }\n\n    static Class<?> getProtoType(String typeName) {\n        if (typeName.equals(\"int\")) {\n            return Integer.TYPE;\n        }\n        if (typeName.equals(\"long\")) {\n            return Long.TYPE;\n        }\n        if (typeName.equals(\"boolean\")) {\n            return Boolean.TYPE;\n        }\n        if (typeName.equals(\"byte\")) {\n            return Byte.TYPE;\n        }\n        if (typeName.equals(\"short\")) {\n            return Short.TYPE;\n        }\n        if (typeName.equals(\"char\")) {\n            return Character.TYPE;\n        }\n        if (typeName.equals(\"float\")) {\n            return Float.TYPE;\n        }\n        if (typeName.equals(\"double\")) {\n            return Double.TYPE;\n        }\n        if (typeName.equals(\"void\")) {\n            return Void.TYPE;\n        }\n        return null;\n    }\n\n\n    public T call(Object... params) {\n        T obj = null;\n        try {\n            obj = (T) method.invoke(null, params);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n    public T callWithException(Object... params) throws Throwable {\n        try {\n            return (T) this.method.invoke(null, params);\n        } catch (InvocationTargetException e) {\n            if (e.getCause() != null) {\n                throw e.getCause();\n            }\n            throw e;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/RefStaticObject.java",
    "content": "package mirror;\n\nimport java.lang.reflect.Field;\n\n@SuppressWarnings(\"unchecked\")\npublic class RefStaticObject<T> {\n    private Field field;\n\n    public RefStaticObject(Class<?> cls, Field field) throws NoSuchFieldException {\n        this.field = cls.getDeclaredField(field.getName());\n        this.field.setAccessible(true);\n    }\n\n    public Class<?> type() {\n        return field.getType();\n    }\n\n    public T get() {\n        T obj = null;\n        try {\n            obj = (T) this.field.get(null);\n        } catch (Exception e) {\n            //Ignore\n        }\n        return obj;\n    }\n\n    public void set(T obj) {\n        try {\n            this.field.set(null, obj);\n        } catch (Exception e) {\n            //Ignore\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/accounts/IAccountManager.java",
    "content": "package mirror.android.accounts;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IAccountManager {\n    public static Class<?> TYPE = RefClass.load(IAccountManager.class, \"android.accounts.IAccountManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.accounts.IAccountManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/Activity.java",
    "content": "package mirror.android.app;\n\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.IBinder;\n\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.RefInt;\n\npublic class Activity {\n    public static Class<?> TYPE = RefClass.load(Activity.class, \"android.app.Activity\");\n    public static RefObject<ActivityInfo> mActivityInfo;\n    public static RefBoolean mFinished;\n    public static RefObject<android.app.Activity> mParent;\n    public static RefInt mResultCode;\n    public static RefObject<Intent> mResultData;\n    public static RefObject<IBinder> mToken;\n    public static RefObject<String> mEmbeddedID;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ActivityManagerNative.java",
    "content": "package mirror.android.app;\n\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticMethod;\n\npublic class ActivityManagerNative {\n    public static Class<?> TYPE = RefClass.load(ActivityManagerNative.class, \"android.app.ActivityManagerNative\");\n    public static RefStaticObject<Object> gDefault;\n    public static RefStaticMethod<IInterface> getDefault;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ActivityManagerOreo.java",
    "content": "package mirror.android.app;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic class ActivityManagerOreo {\n\n    public static Class<?> TYPE = RefClass.load(ActivityManagerOreo.class, \"android.app.ActivityManager\");\n\n    public static RefStaticMethod<IInterface> getService;\n    public static RefStaticObject<Object> IActivityManagerSingleton;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ActivityThread.java",
    "content": "package mirror.android.app;\n\n\nimport android.app.*;\nimport android.app.Activity;\nimport android.app.servertransaction.TransactionExecutor;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ProviderInfo;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\nimport java.util.Map;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefObject;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticInt;\nimport mirror.RefStaticMethod;\n\npublic class ActivityThread {\n    public static Class<?> TYPE = RefClass.load(ActivityThread.class, \"android.app.ActivityThread\");\n    public static RefStaticMethod currentActivityThread;\n    public static RefMethod<String> getProcessName;\n    public static RefMethod<Handler> getHandler;\n    public static RefMethod<Object> installProvider;\n    public static RefObject<Object> mBoundApplication;\n    public static RefObject<Handler> mH;\n    public static RefObject<Application> mInitialApplication;\n    public static RefObject<Instrumentation> mInstrumentation;\n    public static RefObject<Map<String, WeakReference<?>>> mPackages;\n    public static RefObject<Map> mProviderMap;\n    @MethodParams({IBinder.class, List.class})\n    public static RefMethod<Void> performNewIntents;\n    public static RefMethod<Void> handleNewIntent;\n    public static RefStaticObject<IInterface> sPackageManager;\n    @MethodParams({IBinder.class, String.class, int.class, int.class, Intent.class})\n    public static RefMethod<Void> sendActivityResult;\n    public static RefMethod<Binder> getApplicationThread;\n\n    // Android 9.0\n    public static RefObject<TransactionExecutor> mTransactionExecutor;\n\n    public static Object installProvider(Object mainThread, Context context, ProviderInfo providerInfo, Object holder) {\n        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {\n            return installProvider.call(mainThread, context, holder, providerInfo, false, true);\n        }\n        return installProvider.call(mainThread, context, holder, providerInfo, false, true, true);\n    }\n\n    public static class ActivityClientRecord {\n        public static Class<?> TYPE = RefClass.load(ActivityClientRecord.class, \"android.app.ActivityThread$ActivityClientRecord\");\n        public static RefObject<Activity> activity;\n        public static RefObject<ActivityInfo> activityInfo;\n        public static RefObject<Intent> intent;\n        public static RefObject<IBinder> token;\n        public static RefObject<?> packageInfo;\n    }\n\n    public static class ProviderClientRecord {\n        public static Class<?> TYPE = RefClass.load(ProviderClientRecord.class, \"android.app.ActivityThread$ProviderClientRecord\");\n        @MethodReflectParams({\"android.app.ActivityThread\", \"java.lang.String\", \"android.content.IContentProvider\", \"android.content.ContentProvider\"})\n        public static RefConstructor<?> ctor;\n        public static RefObject<String> mName;\n        public static RefObject<IInterface> mProvider;\n    }\n\n\n    public static class ProviderClientRecordJB {\n        public static Class<?> TYPE = RefClass.load(ProviderClientRecordJB.class, \"android.app.ActivityThread$ProviderClientRecord\");\n        public static RefObject<Object> mHolder;\n        public static RefObject<IInterface> mProvider;\n    }\n\n    public static class ProviderKeyJBMR1 {\n        public static Class<?> TYPE = RefClass.load(ProviderKeyJBMR1.class, \"android.app.ActivityThread$ProviderKey\");\n        @MethodParams({String.class, int.class})\n        public static RefConstructor<?> ctor;\n    }\n\n    public static class AppBindData {\n        public static Class<?> TYPE = RefClass.load(AppBindData.class, \"android.app.ActivityThread$AppBindData\");\n        public static RefObject<ApplicationInfo> appInfo;\n        public static RefObject<Object> info;\n        public static RefObject<String> processName;\n        public static RefObject<ComponentName> instrumentationName;\n        public static RefObject<List<ProviderInfo>> providers;\n    }\n\n    public static class H {\n        public static Class<?> TYPE = RefClass.load(H.class, \"android.app.ActivityThread$H\");\n        public static RefStaticInt LAUNCH_ACTIVITY;\n        public static RefStaticInt CREATE_SERVICE;\n        public static RefStaticInt SCHEDULE_CRASH;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ActivityThreadNMR1.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\n\nimport java.util.List;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\n/**\n * @author Lody\n */\n\npublic class ActivityThreadNMR1 {\n    public static Class<?> Class = RefClass.load(ActivityThreadNMR1.class, \"android.app.ActivityThread\");\n    @MethodParams({IBinder.class, List.class, boolean.class})\n    public static RefMethod<Void> performNewIntents;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ApplicationThreadNative.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\npublic class ApplicationThreadNative {\n    public static Class<?> TYPE = RefClass.load(ApplicationThreadNative.class, \"android.app.ApplicationThreadNative\");\n\n    @MethodParams({IBinder.class})\n    public static RefStaticMethod<IInterface> asInterface;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ContextImpl.java",
    "content": "package mirror.android.app;\n\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefObject;\nimport mirror.MethodParams;\n\npublic class ContextImpl {\n    public static Class<?> TYPE = RefClass.load(ContextImpl.class, \"android.app.ContextImpl\");\n    @MethodParams({Context.class})\n    public static RefObject<String> mBasePackageName;\n    public static RefObject<Object> mPackageInfo;\n    public static RefObject<PackageManager> mPackageManager;\n\n    public static RefMethod<Context> getReceiverRestrictedContext;\n\n    public static RefMethod<Object> getAttributionSource;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ContextImplICS.java",
    "content": "package mirror.android.app;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ContextImplICS {\n    public static Class<?> TYPE = RefClass.load(ContextImplICS.class, \"android.app.ContextImpl\");\n    public static RefObject<File> mExternalCacheDir;\n    public static RefObject<File> mExternalFilesDir;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ContextImplKitkat.java",
    "content": "package mirror.android.app;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ContextImplKitkat {\n    public static Class<?> TYPE = RefClass.load(ContextImplKitkat.class, \"android.app.ContextImpl\");\n    public static RefObject<File[]> mExternalCacheDirs;\n    public static RefObject<File[]> mExternalFilesDirs;\n    public static RefObject<String> mOpPackageName;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IActivityManager.java",
    "content": "package mirror.android.app;\n\nimport android.content.pm.ProviderInfo;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\npublic class IActivityManager {\n    public static Class<?> TYPE = RefClass.load(IActivityManager.class, \"android.app.IActivityManager\");\n    @MethodParams({IBinder.class, boolean.class})\n    public static RefMethod<Integer> getTaskForActivity;\n    @MethodParams({IBinder.class, int.class})\n    public static RefMethod<Void> setRequestedOrientation;\n    @MethodParams({IBinder.class, String.class, int.class, int.class})\n    public static RefMethod<Void> overridePendingTransition;\n    public static RefMethod<Integer> startActivity;\n    public static RefMethod<Integer> startActivities;\n\n    public static class ContentProviderHolder {\n        public static Class<?> TYPE = RefClass.load(ContentProviderHolder.class, \"android.app.IActivityManager$ContentProviderHolder\");\n        public static RefObject<ProviderInfo> info;\n        public static RefObject<IInterface> provider;\n        public static RefBoolean noReleaseNeeded;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IActivityManagerICS.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.os.IBinder;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\npublic class IActivityManagerICS {\n    public static Class<?> TYPE = RefClass.load(IActivityManagerICS.class, \"android.app.IActivityManager\");\n    @MethodParams({IBinder.class, int.class, Intent.class})\n    public static RefMethod<Boolean> finishActivity;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IActivityManagerL.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class IActivityManagerL {\n    public static Class<?> TYPE = RefClass.load(IActivityManagerL.class, \"android.app.IActivityManager\");\n    @MethodParams({IBinder.class, int.class, Intent.class, boolean.class})\n    public static RefMethod<Boolean> finishActivity;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IActivityManagerN.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\n/**\n * @author Lody\n */\n\npublic class IActivityManagerN {\n    public static Class<?> TYPE = RefClass.load(IActivityManagerN.class, \"android.app.IActivityManager\");\n    @MethodParams({IBinder.class, int.class, Intent.class, int.class})\n    public static RefMethod<Boolean> finishActivity;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IActivityTaskManager.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author weishu\n * @date 2019-11-05.\n */\npublic class IActivityTaskManager {\n    public static Class<?> TYPE = RefClass.load(IActivityTaskManager.class, \"android.app.IActivityTaskManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(IActivityTaskManager.Stub.class, \"android.app.IActivityTaskManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IAlarmManager.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class IAlarmManager {\n    public static Class<?> TYPE = RefClass.load(IAlarmManager.class, \"android.app.IAlarmManager\");\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.app.IAlarmManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IApplicationThread.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.IBinder;\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThread {\n    public static Class<?> TYPE = RefClass.load(IApplicationThread.class, \"android.app.IApplicationThread\");\n\n    @MethodParams({List.class, IBinder.class})\n    public static RefMethod<Void> scheduleNewIntent;\n\n    @MethodParams({IBinder.class, ServiceInfo.class})\n    public static RefMethod<Void> scheduleCreateService;\n\n    @MethodParams({IBinder.class, Intent.class, boolean.class})\n    public static RefMethod<Void> scheduleBindService;\n\n    @MethodParams({IBinder.class, Intent.class})\n    public static RefMethod<Void> scheduleUnbindService;\n\n    @MethodParams({IBinder.class, int.class, int.class, Intent.class})\n    public static RefMethod<Void> scheduleServiceArgs;\n\n    @MethodParams({IBinder.class})\n    public static RefMethod<Void> scheduleStopService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IApplicationThreadICSMR1.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.IBinder;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.android.content.res.CompatibilityInfo;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThreadICSMR1 {\n    public static Class<?> TYPE = RefClass.load(IApplicationThreadICSMR1.class, \"android.app.IApplicationThread\");\n\n    @MethodReflectParams({\"android.content.Intent\", \"android.content.pm.ActivityInfo\", \"android.content.res.CompatibilityInfo\", \"int\", \"java.lang.String\", \"android.os.Bundle\", \"boolean\"})\n    public static RefMethod<Void> scheduleReceiver;\n\n    @MethodParams({IBinder.class, ServiceInfo.class, CompatibilityInfo.class})\n    public static RefMethod<Void> scheduleCreateService;\n\n    @MethodParams({IBinder.class, boolean.class, int.class, int.class, Intent.class})\n    public static RefMethod<Void> scheduleServiceArgs;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IApplicationThreadJBMR1.java",
    "content": "package mirror.android.app;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodReflectParams;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThreadJBMR1 {\n    public static Class<?> TYPE = RefClass.load(IApplicationThreadJBMR1.class, \"android.app.IApplicationThread\");\n\n    @MethodReflectParams({\"android.content.Intent\", \"android.content.pm.ActivityInfo\", \"android.content.res.CompatibilityInfo\", \"int\", \"java.lang.String\", \"android.os.Bundle\", \"boolean\", \"int\"})\n    public static RefMethod<Void> scheduleReceiver;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IApplicationThreadKitkat.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.IBinder;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.android.content.res.CompatibilityInfo;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThreadKitkat {\n    public static Class<?> TYPE = RefClass.load(IApplicationThreadKitkat.class, \"android.app.IApplicationThread\");\n\n    @MethodReflectParams({\"android.content.Intent\", \"android.content.pm.ActivityInfo\", \"android.content.res.CompatibilityInfo\", \"int\", \"java.lang.String\", \"android.os.Bundle\", \"boolean\", \"int\", \"int\"})\n    public static RefMethod<Void> scheduleReceiver;\n\n    @MethodParams({IBinder.class, ServiceInfo.class, CompatibilityInfo.class, int.class})\n    public static RefMethod<Void> scheduleCreateService;\n\n    @MethodParams({IBinder.class, Intent.class, boolean.class, int.class})\n    public static RefMethod<Void> scheduleBindService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IApplicationThreadOreo.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class IApplicationThreadOreo {\n\n    public static Class<?> TYPE = RefClass.load(IApplicationThreadOreo.class, \"android.app.IApplicationThread\");\n\n    public static final class Stub {\n        public static Class<?> TYPE = RefClass.load(IApplicationThreadOreo.Stub.class, \"android.app.IApplicationThread$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n\n    @MethodReflectParams({\"android.os.IBinder\", \"android.content.pm.ParceledListSlice\"})\n    public static RefMethod<Void> scheduleServiceArgs;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ISearchManager.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class ISearchManager {\n    public static Class<?> TYPE = RefClass.load(ISearchManager.class, \"android.app.ISearchManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.app.ISearchManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IServiceConnectionO.java",
    "content": "package mirror.android.app;\n\nimport android.content.ComponentName;\nimport android.os.IBinder;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\npublic class IServiceConnectionO {\n    public static Class<?> TYPE = RefClass.load(IServiceConnectionO.class, \"android.app.IServiceConnection\");\n\n    @MethodParams({ComponentName.class, IBinder.class, boolean.class})\n    public static RefMethod<Void> connected;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/IUsageStatsManager.java",
    "content": "package mirror.android.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * Created by caokai on 2017/9/8.\n */\n\npublic class IUsageStatsManager {\n    public static Class<?> TYPE = RefClass.load(IUsageStatsManager.class, \"android.app.usage.IUsageStatsManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(IUsageStatsManager.Stub.class, \"android.app.usage.IUsageStatsManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/LoadedApk.java",
    "content": "package mirror.android.app;\n\nimport android.app.Application;\nimport android.app.IServiceConnection;\nimport android.app.Instrumentation;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.IIntentReceiver;\nimport android.content.ServiceConnection;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Handler;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\npublic class LoadedApk {\n    public static Class Class = RefClass.load(LoadedApk.class, \"android.app.LoadedApk\");\n    public static RefObject<ApplicationInfo> mApplicationInfo;\n    @MethodParams({boolean.class, Instrumentation.class})\n    public static RefMethod<Application> makeApplication;\n    @MethodParams({ServiceConnection.class, Context.class, Handler.class, int.class})\n    public static RefMethod<IServiceConnection> getServiceDispatcher;\n    @MethodParams({Context.class, ServiceConnection.class})\n    public static RefMethod<IServiceConnection> forgetServiceDispatcher;\n\n    public static RefMethod<ClassLoader> getClassLoader;\n\n    public static class ReceiverDispatcher {\n        public static Class Class = RefClass.load(ReceiverDispatcher.class, \"android.app.LoadedApk$ReceiverDispatcher\");\n        public static RefMethod<IInterface> getIIntentReceiver;\n        public static RefObject<BroadcastReceiver> mReceiver;\n        public static RefObject<IIntentReceiver> mIIntentReceiver;\n\n        public static class InnerReceiver {\n            public static Class Class = RefClass.load(InnerReceiver.class, \"android.app.LoadedApk$ReceiverDispatcher$InnerReceiver\");\n            public static RefObject<WeakReference> mDispatcher;\n        }\n    }\n\n    public static class ServiceDispatcher {\n        public static Class Class = RefClass.load(ServiceDispatcher.class, \"android.app.LoadedApk$ServiceDispatcher\");\n        public static RefObject<ServiceConnection> mConnection;\n        public static RefObject<Context> mContext;\n\n        public static class InnerConnection {\n            public static Class Class = RefClass.load(InnerConnection.class, \"android.app.LoadedApk$ServiceDispatcher$InnerConnection\");\n            public static RefObject<WeakReference> mDispatcher;\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/LoadedApkHuaWei.java",
    "content": "package mirror.android.app;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class LoadedApkHuaWei {\n    public static Class<?> TYPE = RefClass.load(LoadedApkHuaWei.class, \"android.app.LoadedApk\");\n    public static RefObject<Object> mReceiverResource;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/Notification.java",
    "content": "package mirror.android.app;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\npublic class Notification {\n    public static Class<?> TYPE = RefClass.load(Notification.class, android.app.Notification.class);\n    @MethodParams({Context.class, CharSequence.class, CharSequence.class, PendingIntent.class})\n    public static RefMethod<Void> setLatestEventInfo;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/NotificationL.java",
    "content": "package mirror.android.app;\n\nimport android.app.Notification;\nimport android.content.Context;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class NotificationL {\n    public static Class<?> TYPE = RefClass.load(NotificationL.class, Notification.class);\n\n    public static class Builder {\n        public static Class<?> TYPE = RefClass.load(Builder.class, android.app.Notification.Builder.class);\n\n        @MethodParams({Context.class, Notification.class})\n        public static RefStaticMethod<Notification> rebuild;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/NotificationM.java",
    "content": "package mirror.android.app;\n\n\nimport android.app.Notification;\nimport android.graphics.drawable.Icon;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class NotificationM {\n    public static Class<?> TYPE = RefClass.load(NotificationM.class, Notification.class);\n    public static RefObject<Icon> mLargeIcon;\n    public static RefObject<Icon> mSmallIcon;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/NotificationManager.java",
    "content": "package mirror.android.app;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticMethod;\n\npublic class NotificationManager {\n    public static Class<?> TYPE = RefClass.load(NotificationManager.class, \"android.app.NotificationManager\");\n\n    public static RefStaticMethod<IInterface> getService;\n    public static RefStaticObject<IInterface> sService;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/PendingIntentJBMR2.java",
    "content": "package mirror.android.app;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\npublic class PendingIntentJBMR2 {\n    public static Class Class = RefClass.load(PendingIntentJBMR2.class, PendingIntent.class);\n    public static RefMethod<Intent> getIntent;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/ServiceStartArgs.java",
    "content": "package mirror.android.app;\n\nimport android.content.Intent;\n\nimport mirror.MethodParams;\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\npublic class ServiceStartArgs {\n    public static Class<?> TYPE = RefClass.load(ServiceStartArgs.class, \"android.app.ServiceStartArgs\");\n    @MethodParams({boolean.class, int.class, int.class, Intent.class})\n    public static RefConstructor<Object> ctor;\n    public static RefBoolean taskRemoved;\n    public static RefInt startId;\n    public static RefInt flags;\n    public static RefObject<Intent> args;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/admin/IDevicePolicyManager.java",
    "content": "package mirror.android.app.admin;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * Created by wy on 2017/10/20.\n */\n\npublic class IDevicePolicyManager {\n    public static Class<?> TYPE = RefClass.load(IDevicePolicyManager.class, \"android.app.admin.IDevicePolicyManager\");\n\n    public static class  Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.app.admin.IDevicePolicyManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/backup/IBackupManager.java",
    "content": "package mirror.android.app.backup;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IBackupManager {\n    public static Class<?> TYPE = RefClass.load(IBackupManager.class, \"android.app.backup.IBackupManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.app.backup.IBackupManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/job/IJobScheduler.java",
    "content": "package mirror.android.app.job;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IJobScheduler {\n    public static Class<?> TYPE = RefClass.load(IJobScheduler.class, \"android.app.job.IJobScheduler\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.app.job.IJobScheduler$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/job/JobInfo.java",
    "content": "package mirror.android.app.job;\n\nimport android.annotation.TargetApi;\nimport android.content.ComponentName;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefInt;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class JobInfo {\n    public static Class<?> TYPE = RefClass.load(JobInfo.class, android.app.job.JobInfo.class);\n\n    public static RefInt jobId;\n    public static RefObject<ComponentName> service;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/job/JobParameters.java",
    "content": "package mirror.android.app.job;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.PersistableBundle;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.LOLLIPOP)\npublic class JobParameters {\n    public static Class<?> TYPE = RefClass.load(JobParameters.class, android.app.job.JobParameters.class);\n\n    public static RefObject<IBinder> callback;\n    public static RefObject<PersistableBundle> extras;\n    public static RefInt jobId;\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/app/job/JobWorkItem.java",
    "content": "package mirror.android.app.job;\n\nimport android.annotation.TargetApi;\nimport android.content.Intent;\nimport android.os.Build;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.O)\npublic class JobWorkItem {\n    public static Class<?> TYPE = RefClass.load(JobWorkItem.class, android.app.job.JobWorkItem.class);\n\n//    final Intent mIntent;\n//    int mDeliveryCount;\n//    int mWorkId;\n//    Object mGrants;\n    @MethodParams({Intent.class})\n    public static RefConstructor<android.app.job.JobWorkItem> ctor;\n\n    public static RefObject<Intent> mIntent;\n    public static RefObject<Integer> mDeliveryCount;\n    public static RefObject<Integer> mWorkId;\n    public static RefObject<Object> mGrants;\n\n    public static RefMethod<Intent> getIntent;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/bluetooth/IBluetooth.java",
    "content": "package mirror.android.bluetooth;\r\n\r\nimport android.os.IBinder;\r\nimport android.os.IInterface;\r\n\r\nimport mirror.MethodParams;\r\nimport mirror.RefClass;\r\nimport mirror.RefStaticMethod;\r\n\r\npublic class IBluetooth {\r\n    /**\r\n     * @see android.bluetooth.IBluetooth\r\n     * */\r\n    public static Class<?> TYPE = RefClass.load(IBluetooth.class, \"android.bluetooth.IBluetooth\");\r\n    /**\r\n     * @see android.bluetooth.IBluetooth.Stub\r\n     * */\r\n    public static class Stub {\r\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.bluetooth.IBluetooth$Stub\");\r\n        @MethodParams({IBinder.class})\r\n        public static RefStaticMethod<IInterface> asInterface;\r\n    }\r\n}\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/BroadcastReceiver.java",
    "content": "package mirror.android.content;\n\n\nimport android.os.Bundle;\nimport android.os.IBinder;\n\nimport mirror.MethodParams;\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\npublic class BroadcastReceiver {\n    public static Class<?> TYPE = RefClass.load(BroadcastReceiver.class, android.content.BroadcastReceiver.class);\n    public static RefMethod<android.content.BroadcastReceiver.PendingResult> getPendingResult;\n    @MethodParams({android.content.BroadcastReceiver.PendingResult.class})\n    public static RefMethod<Void> setPendingResult;\n\n    public static class PendingResult {\n        public static Class<?> TYPE = RefClass.load(PendingResult.class, android.content.BroadcastReceiver.PendingResult.class);\n        @MethodParams({int.class, String.class, Bundle.class, int.class, boolean.class, boolean.class, IBinder.class})\n        public static RefConstructor<android.content.BroadcastReceiver.PendingResult> ctor;\n        public static RefBoolean mAbortBroadcast;\n        public static RefBoolean mFinished;\n        public static RefBoolean mInitialStickyHint;\n        public static RefBoolean mOrderedHint;\n        public static RefInt mResultCode;\n        public static RefObject<String> mResultData;\n        public static RefObject<Bundle> mResultExtras;\n        public static RefObject<IBinder> mToken;\n        public static RefInt mType;\n    }\n\n    public static class PendingResultJBMR1 {\n        public static Class<?> TYPE = RefClass.load(PendingResultJBMR1.class, android.content.BroadcastReceiver.PendingResult.class);\n        @MethodParams({int.class, String.class, Bundle.class, int.class, boolean.class, boolean.class, IBinder.class, int.class})\n        public static RefConstructor<android.content.BroadcastReceiver.PendingResult> ctor;\n        public static RefBoolean mAbortBroadcast;\n        public static RefBoolean mFinished;\n        public static RefBoolean mInitialStickyHint;\n        public static RefBoolean mOrderedHint;\n        public static RefInt mResultCode;\n        public static RefObject<String> mResultData;\n        public static RefObject<Bundle> mResultExtras;\n        public static RefInt mSendingUser;\n        public static RefObject<IBinder> mToken;\n        public static RefInt mType;\n    }\n\n    public static class PendingResultMNC {\n        public static Class<?> TYPE = RefClass.load(PendingResultMNC.class, android.content.BroadcastReceiver.PendingResult.class);\n        @MethodParams({int.class, String.class, Bundle.class, int.class, boolean.class, boolean.class, IBinder.class, int.class, int.class})\n        public static RefConstructor<android.content.BroadcastReceiver.PendingResult> ctor;\n        public static RefBoolean mAbortBroadcast;\n        public static RefBoolean mFinished;\n        public static RefInt mFlags;\n        public static RefBoolean mInitialStickyHint;\n        public static RefBoolean mOrderedHint;\n        public static RefInt mResultCode;\n        public static RefObject<String> mResultData;\n        public static RefObject<Bundle> mResultExtras;\n        public static RefInt mSendingUser;\n        public static RefObject<IBinder> mToken;\n        public static RefInt mType;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ClipboardManager.java",
    "content": "package mirror.android.content;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticMethod;\n\npublic class ClipboardManager {\n    public static Class<?> TYPE = RefClass.load(ClipboardManager.class, android.content.ClipboardManager.class);\n    public static RefStaticMethod<IInterface> getService;\n    public static RefStaticObject<IInterface> sService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ClipboardManagerOreo.java",
    "content": "package mirror.android.content;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ClipboardManagerOreo {\n    public static Class<?> TYPE = RefClass.load(ClipboardManagerOreo.class, android.content.ClipboardManager.class);\n    public static RefObject<IInterface> mService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ContentProviderClient.java",
    "content": "package mirror.android.content;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ContentProviderClient {\n    public static Class Class = RefClass.load(ContentProviderClient.class, android.content.ContentProviderClient.class);\n    public static RefObject<IInterface> mContentProvider;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ContentProviderHolderOreo.java",
    "content": "package mirror.android.content;\n\nimport android.content.pm.ProviderInfo;\nimport android.os.IInterface;\n\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class ContentProviderHolderOreo {\n    public static Class<?> TYPE = RefClass.load(ContentProviderHolderOreo.class, \"android.app.ContentProviderHolder\");\n    public static RefObject<ProviderInfo> info;\n    public static RefObject<IInterface> provider;\n    public static RefBoolean noReleaseNeeded;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ContentProviderNative.java",
    "content": "package mirror.android.content;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class ContentProviderNative {\n    public static Class<?> TYPE = RefClass.load(ContentProviderNative.class, \"android.content.ContentProviderNative\");\n    @MethodParams({IBinder.class})\n    public static RefStaticMethod<IInterface> asInterface;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ContentResolver.java",
    "content": "package mirror.android.content;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic class ContentResolver {\n    public static Class<?> TYPE = RefClass.load(ContentResolver.class, android.content.ContentResolver.class);\n    public static RefStaticObject<IInterface> sContentService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/ContentResolverJBMR2.java",
    "content": "package mirror.android.content;\n\nimport android.content.ContentResolver;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ContentResolverJBMR2 {\n    public static Class Class = RefClass.load(ContentResolverJBMR2.class, ContentResolver.class);;\n    public static RefObject<String> mPackageName;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IClipboard.java",
    "content": "package mirror.android.content;\n\nimport mirror.RefClass;\n\npublic class IClipboard {\n    public static Class<?> TYPE = RefClass.load(IClipboard.class, \"android.content.IClipboard\");\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IContentProvider.java",
    "content": "package mirror.android.content;\n\nimport mirror.RefClass;\n\n/**\n * @author Lody\n */\n\npublic class IContentProvider {\n    public static Class<?> TYPE = RefClass.load(IContentProvider.class, \"android.content.IContentProvider\");\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IContentService.java",
    "content": "package mirror.android.content;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class IContentService {\n    public static Class<?> TYPE = RefClass.load(IContentService.class, \"android.content.IContentService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.content.IContentService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IIntentReceiver.java",
    "content": "package mirror.android.content;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class IIntentReceiver {\n    public static Class<?> TYPE = RefClass.load(IIntentReceiver.class, \"android.content.IIntentReceiver\");\n\n    @MethodParams({Intent.class, int.class,\n            String.class, Bundle.class, boolean.class, boolean.class})\n    public static RefMethod<Void> performReceive;\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IIntentReceiverJB.java",
    "content": "package mirror.android.content;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class IIntentReceiverJB {\n    public static Class<?> TYPE = RefClass.load(IIntentReceiverJB.class, \"android.content.IIntentReceiver\");\n\n    @MethodParams({Intent.class, int.class,\n            String.class, Bundle.class, boolean.class, boolean.class, int.class})\n    public static RefMethod<Void> performReceive;\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IRestrictionsManager.java",
    "content": "package mirror.android.content;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IRestrictionsManager {\n    public static Class<?> TYPE = RefClass.load(IRestrictionsManager.class, \"android.content.IRestrictionsManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.content.IRestrictionsManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/IntentFilter.java",
    "content": "package mirror.android.content;\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class IntentFilter {\n    public static Class Class = RefClass.load(IntentFilter.class, android.content.IntentFilter.class);\n    public static RefObject<List<String>> mActions;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/SyncAdapterType.java",
    "content": "package mirror.android.content;\n\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\n\npublic class SyncAdapterType {\n    public static Class<?> TYPE = RefClass.load(SyncAdapterType.class, android.content.SyncAdapterType.class);\n    @MethodParams({String.class, String.class, boolean.class, boolean.class, boolean.class, boolean.class, String.class})\n    public static RefConstructor<android.content.SyncAdapterType> ctor;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/SyncAdapterTypeN.java",
    "content": "package mirror.android.content;\n\nimport android.content.SyncAdapterType;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\n\npublic class SyncAdapterTypeN {\n    public static Class<?> Class = RefClass.load(SyncAdapterTypeN.class, SyncAdapterType.class);\n    @MethodParams({String.class, String.class, boolean.class, boolean.class, boolean.class, boolean.class, String.class, String.class})\n    public static RefConstructor<SyncAdapterType> ctor;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/SyncInfo.java",
    "content": "package mirror.android.content;\n\nimport android.accounts.Account;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\n\npublic class SyncInfo {\n    public static Class<?> TYPE = RefClass.load(SyncInfo.class, android.content.SyncInfo.class);\n    @MethodParams({int.class, Account.class, String.class, long.class})\n    public static RefConstructor<android.content.SyncInfo> ctor;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/SyncRequest.java",
    "content": "package mirror.android.content;\n\n\nimport android.accounts.Account;\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefLong;\nimport mirror.RefObject;\n\n@TargetApi(Build.VERSION_CODES.KITKAT)\npublic class SyncRequest {\n    public static Class<?> TYPE = RefClass.load(SyncRequest.class, android.content.SyncRequest.class);\n    public static RefObject<Account> mAccountToSync;\n    public static RefObject<String> mAuthority;\n    public static RefObject<Bundle> mExtras;\n    public static RefBoolean mIsPeriodic;\n    public static RefLong mSyncRunTimeSecs;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ApplicationInfoL.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.ApplicationInfo;\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ApplicationInfoL {\n    public static Class<?> TYPE = RefClass.load(ApplicationInfoL.class, ApplicationInfo.class);\n    public static RefObject<String> primaryCpuAbi;\n    public static RefObject<String> scanPublicSourceDir;\n    public static RefObject<String> scanSourceDir;\n    public static RefObject<String[]> splitPublicSourceDirs;\n    public static RefObject<String[]> splitSourceDirs;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ApplicationInfoN.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.ApplicationInfo;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ApplicationInfoN {\n    public static Class<?> TYPE = RefClass.load(ApplicationInfoN.class, ApplicationInfo.class);\n    public static RefObject<String> deviceProtectedDataDir;\n    public static RefObject<String> deviceEncryptedDataDir;\n    public static RefObject<String> credentialProtectedDataDir;\n    public static RefObject<String> credentialEncryptedDataDir;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ILauncherApps.java",
    "content": "package mirror.android.content.pm;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\npublic class ILauncherApps {\n\n    public static final class Stub {\n        public static Class<?> TYPE = RefClass.load(ILauncherApps.class, \"android.content.pm.ILauncherApps$Stub\");\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/IShortcutService.java",
    "content": "package mirror.android.content.pm;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class IShortcutService {\n\n    public static final class Stub {\n        public static Class<?> TYPE = RefClass.load(IShortcutService.Stub.class, \"android.content.pm.IShortcutService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/LauncherApps.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.PackageManager;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.com.android.internal.os.UserManager;\n\n/**\n * @author Lody\n */\n\npublic class LauncherApps {\n\n    public static Class<?> TYPE = RefClass.load(LauncherApps.class, \"android.content.pm.LauncherApps\");\n\n    public static RefObject<PackageManager> mPm;\n    public static RefObject<IInterface> mService;\n    public static RefObject<UserManager> mUserManager;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageInstaller.java",
    "content": "package mirror.android.content.pm;\n\n\nimport android.graphics.Bitmap;\nimport android.net.Uri;\n\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefFloat;\nimport mirror.RefInt;\nimport mirror.RefLong;\nimport mirror.RefObject;\n\npublic class PackageInstaller {\n\n    public static class SessionInfo {\n        public static Class<?> TYPE = RefClass.load(SessionInfo.class, \"android.content.pm.PackageInstaller$SessionInfo\");\n        public static RefBoolean active;\n        public static RefObject<Bitmap> appIcon;\n        public static RefObject<CharSequence> appLabel;\n        public static RefObject<String> appPackageName;\n        public static RefConstructor<android.content.pm.PackageInstaller.SessionInfo> ctor;\n        public static RefObject<String> installerPackageName;\n        public static RefInt mode;\n        public static RefFloat progress;\n        public static RefObject<String> resolvedBaseCodePath;\n        public static RefBoolean sealed;\n        public static RefInt sessionId;\n        public static RefLong sizeBytes;\n    }\n\n    public static class SessionParamsLOLLIPOP {\n        public static Class<?> TYPE = RefClass.load(SessionParamsLOLLIPOP.class, \"android.content.pm.PackageInstaller$SessionParams\");\n        public static RefObject<String> abiOverride;\n        public static RefObject<Bitmap> appIcon;\n        public static RefLong appIconLastModified;\n        public static RefObject<String> appLabel;\n        public static RefObject<String> appPackageName;\n        public static RefInt installFlags;\n        public static RefInt installLocation;\n        public static RefInt mode;\n        public static RefObject<Uri> originatingUri;\n        public static RefObject<Uri> referrerUri;\n        public static RefLong sizeBytes;\n    }\n\n    public static class SessionParamsMarshmallow {\n        public static Class<?> TYPE = RefClass.load(SessionParamsMarshmallow.class, \"android.content.pm.PackageInstaller$SessionParams\");\n        public static RefObject<String> abiOverride;\n        public static RefObject<Bitmap> appIcon;\n        public static RefLong appIconLastModified;\n        public static RefObject<String> appLabel;\n        public static RefObject<String> appPackageName;\n        public static RefObject<String[]> grantedRuntimePermissions;\n        public static RefInt installFlags;\n        public static RefInt installLocation;\n        public static RefInt mode;\n        public static RefObject<Uri> originatingUri;\n        public static RefObject<Uri> referrerUri;\n        public static RefLong sizeBytes;\n        public static RefObject<String> volumeUuid;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.ComponentName;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.Signature;\nimport android.os.Bundle;\nimport android.util.DisplayMetrics;\n\nimport java.io.File;\nimport java.util.List;\n\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.RefObject;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParser {\n\n    public static Class<?> TYPE = RefClass.load(PackageParser.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    @MethodParams({String.class})\n    public static RefConstructor<android.content.pm.PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, String.class, DisplayMetrics.class, int.class})\n    public static RefMethod<android.content.pm.PackageParser.Package> parsePackage;\n    \n    public static class Package {\n        public static Class<?> TYPE = RefClass.load(Package.class, \"android.content.pm.PackageParser$Package\");\n        public static RefObject<List> activities;\n        public static RefObject<Bundle> mAppMetaData;\n        public static RefObject<String> mSharedUserId;\n        public static RefObject<Signature[]> mSignatures;\n        public static RefObject<Integer> mVersionCode;\n        public static RefObject<String> packageName;\n        public static RefObject<List> permissionGroups;\n        public static RefObject<List> permissions;\n        public static RefObject<List<String>> protectedBroadcasts;\n        public static RefObject<List> providers;\n        public static RefObject<List> receivers;\n        public static RefObject<List<String>> requestedPermissions;\n        public static RefObject<List> services;\n        public static RefObject<Object> mSigningDetails;\n    }\n\n    public static class Activity {\n        public static Class<?> TYPE = RefClass.load(Activity.class, \"android.content.pm.PackageParser$Activity\");\n        public static RefObject<ActivityInfo> info;\n    }\n\n    public static class Provider {\n        public static Class<?> TYPE = RefClass.load(Provider.class, \"android.content.pm.PackageParser$Provider\");\n        public static RefObject<ProviderInfo> info;\n    }\n\n    public static class Service {\n        public static Class<?> TYPE = RefClass.load(Provider.class, \"android.content.pm.PackageParser$Service\");\n        public static RefObject<ServiceInfo> info;\n    }\n\n\n\n\n    public static class Permission {\n        public static Class<?> TYPE = RefClass.load(Permission.class, \"android.content.pm.PackageParser$Permission\");\n        public static RefObject<PermissionInfo> info;\n    }\n\n    public static class PermissionGroup {\n        public static Class<?> TYPE = RefClass.load(PermissionGroup.class, \"android.content.pm.PackageParser$PermissionGroup\");\n        public static RefObject<PermissionGroupInfo> info;\n    }\n\n    public static class Component {\n        public static Class<?> TYPE = RefClass.load(Component.class, \"android.content.pm.PackageParser$Component\");\n        public static RefObject<String> className;\n        public static RefObject<ComponentName> componentName;\n        public static RefObject<List<IntentFilter>> intents;\n    }\n\n    public static class SigningInfo {\n        public static Class<?> TYPE = RefClass.load(SigningInfo.class, \"android.content.pm.SigningInfo\");\n\n        @MethodReflectParams(\"android.content.pm.PackageParser$SigningDetails\")\n        public static RefConstructor<android.content.pm.SigningInfo> ctor;\n    }\n\n    public static class SigningDetails {\n        public static Class<?> TYPE = RefClass.load(SigningDetails.class, \"android.content.pm.PackageParser$SigningDetails\");\n        public static RefObject<Signature[]> signatures;\n        public static RefObject<Signature[]> pastSigningCertificates;\n\n        public static RefMethod<Boolean> hasPastSigningCertificates;\n        public static RefMethod<Boolean> hasSignatures;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserJellyBean.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.*;\nimport android.content.pm.PackageParser;\nimport android.util.DisplayMetrics;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserJellyBean {\n    public static Class<?> TYPE = RefClass.load(PackageParserJellyBean.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    @MethodParams({String.class})\n    public static RefConstructor<PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\", \"boolean\", \"int\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\", \"boolean\", \"int\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\", \"java.util.HashSet\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\", \"boolean\", \"int\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\", \"boolean\", \"int\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, String.class, DisplayMetrics.class, int.class})\n    public static RefMethod<PackageParser.Package> parsePackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserJellyBean17.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.*;\nimport android.content.pm.PackageParser;\nimport android.util.DisplayMetrics;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserJellyBean17 {\n    public static Class<?> TYPE = RefClass.load(PackageParserJellyBean17.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    @MethodParams({String.class})\n    public static RefConstructor<PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\", \"java.util.HashSet\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, String.class, DisplayMetrics.class, int.class})\n    public static RefMethod<PackageParser.Package> parsePackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserLollipop.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.*;\nimport android.content.pm.PackageParser;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserLollipop {\n    public static Class<?> TYPE = RefClass.load(PackageParserLollipop.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    public static RefConstructor<PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\", \"java.util.HashSet\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, int.class})\n    public static RefMethod<PackageParser.Package> parsePackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserLollipop22.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.*;\nimport android.content.pm.PackageParser;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserLollipop22 {\n    public static Class<?> TYPE = RefClass.load(PackageParserLollipop22.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    public static RefConstructor<PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\", \"android.util.ArraySet\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, int.class})\n    public static RefMethod<PackageParser.Package> parsePackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserMarshmallow.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.*;\nimport android.content.pm.PackageParser;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserMarshmallow {\n    public static Class<?> TYPE = RefClass.load(PackageParserMarshmallow.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefMethod<Void> collectCertificates;\n    public static RefConstructor<PackageParser> ctor;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Activity\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ActivityInfo> generateActivityInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<ApplicationInfo> generateApplicationInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"[I\", \"int\", \"long\", \"long\", \"java.util.Set\", \"android.content.pm.PackageUserState\"})\n    public static RefStaticMethod<PackageInfo> generatePackageInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Provider\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ProviderInfo> generateProviderInfo;\n    @MethodReflectParams({\"android.content.pm.PackageParser$Service\", \"int\", \"android.content.pm.PackageUserState\", \"int\"})\n    public static RefStaticMethod<ServiceInfo> generateServiceInfo;\n    @MethodParams({File.class, int.class})\n    public static RefMethod<PackageParser.Package> parsePackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserNougat.java",
    "content": "package mirror.android.content.pm;\n\nimport mirror.MethodReflectParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class PackageParserNougat {\n    public static Class<?> TYPE = RefClass.load(PackageParserNougat.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"int\"})\n    public static RefStaticMethod<Void> collectCertificates;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParserP28.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.pm.PackageManager;\n\nimport mirror.MethodParams;\nimport mirror.MethodReflectParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.RefStaticMethod;\n\n/**\n * @author weishu\n * @date 2018/6/7.\n */\n\npublic class PackageParserP28 {\n    public static Class<?> TYPE = RefClass.load(PackageParserP28.class, \"android.content.pm.PackageParser\");\n    @MethodReflectParams({\"android.content.pm.PackageParser$Package\", \"boolean\"})\n    public static RefStaticMethod<Void> collectCertificates;\n\n    @MethodReflectParams({\"android.content.pm.PackageParser$Callback\"})\n    public static RefMethod<Void> setCallback;\n\n    public static class CallbackImpl {\n        public static Class<?> CLASS = RefClass.load(PackageParserP28.CallbackImpl.class, \"android.content.pm.PackageParser$CallbackImpl\");\n\n        @MethodParams({PackageManager.class})\n        public static RefConstructor<Object> ctor;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageUserState.java",
    "content": "package mirror.android.content.pm;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\n\npublic class PackageUserState {\n    public static Class<?> TYPE = RefClass.load(PackageUserState.class, \"android.content.pm.PackageUserState\");\n    public static RefConstructor<Object> ctor;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ParceledListSlice.java",
    "content": "package mirror.android.content.pm;\n\nimport android.os.Parcelable;\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic class ParceledListSlice {\n    public static RefStaticObject<Parcelable.Creator> CREATOR;\n    public static Class<?> TYPE = RefClass.load(ParceledListSlice.class, \"android.content.pm.ParceledListSlice\");\n    public static RefMethod<Boolean> append;\n    public static RefConstructor<Parcelable> ctor;\n    public static RefMethod<Boolean> isLastSlice;\n    public static RefMethod<Parcelable> populateList;\n    public static RefMethod<Void> setLastSlice;\n    public static RefMethod<List<?>> getList;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ParceledListSliceJBMR2.java",
    "content": "package mirror.android.content.pm;\n\nimport android.os.Parcelable;\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic class ParceledListSliceJBMR2 {\n    public static RefStaticObject<Parcelable.Creator> CREATOR;\n    public static Class<?> TYPE = RefClass.load(ParceledListSliceJBMR2.class, \"android.content.pm.ParceledListSlice\");\n    @MethodParams({List.class})\n    public static RefConstructor<Parcelable> ctor;\n    public static RefMethod<List> getList;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/ShortcutInfo.java",
    "content": "package mirror.android.content.pm;\n\nimport android.content.Intent;\nimport android.graphics.drawable.Icon;\nimport android.os.PersistableBundle;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * author: weishu on 18/3/3.\n */\n\npublic class ShortcutInfo {\n    public static Class<?> TYPE = RefClass.load(ShortcutInfo.class, \"android.content.pm.ShortcutInfo\");\n    public static RefObject<String> mPackageName;\n    public static RefObject<Icon> mIcon;\n    public static RefObject<Intent[]> mIntents;\n    public static RefObject<PersistableBundle[]> mIntentPersistableExtrases;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/pm/UserInfo.java",
    "content": "package mirror.android.content.pm;\n\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefStaticInt;\n\npublic class UserInfo {\n    public static Class<?> TYPE = RefClass.load(UserInfo.class, \"android.content.pm.UserInfo\");\n    public static RefStaticInt FLAG_PRIMARY;\n    @MethodParams({int.class, String.class, int.class})\n    public static RefConstructor<Object> ctor;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/res/AssetManager.java",
    "content": "package mirror.android.content.res;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class AssetManager {\n    public static Class<?> TYPE = RefClass.load(AssetManager.class, android.content.res.AssetManager.class);\n    public static RefConstructor<android.content.res.AssetManager> ctor;\n    @MethodParams(String.class)\n    public static RefMethod<Integer> addAssetPath;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/content/res/CompatibilityInfo.java",
    "content": "package mirror.android.content.res;\n\nimport android.content.pm.ApplicationInfo;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.MethodParams;\nimport mirror.RefStaticObject;\n\npublic class CompatibilityInfo {\n    public static Class<?> TYPE = RefClass.load(CompatibilityInfo.class, \"android.content.res.CompatibilityInfo\");\n    @MethodParams({ApplicationInfo.class, int.class, int.class, boolean.class})\n    public static RefConstructor ctor;\n    public static RefStaticObject<Object> DEFAULT_COMPATIBILITY_INFO;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/ddm/DdmHandleAppName.java",
    "content": "package mirror.android.ddm;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class DdmHandleAppName {\n    public static Class Class = RefClass.load(DdmHandleAppName.class, \"android.ddm.DdmHandleAppName\");\n    @MethodParams({String.class})\n    public static RefStaticMethod<Void> setAppName;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/ddm/DdmHandleAppNameJBMR1.java",
    "content": "package mirror.android.ddm;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class DdmHandleAppNameJBMR1 {\n    public static Class Class = RefClass.load(DdmHandleAppNameJBMR1.class, \"android.ddm.DdmHandleAppName\");\n    @MethodParams({String.class, int.class})\n    public static RefStaticMethod<Void> setAppName;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/graphics/drawable/Icon.java",
    "content": "package mirror.android.graphics.drawable;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n@TargetApi(Build.VERSION_CODES.M)\npublic class Icon {\n    public static final int TYPE_BITMAP   = 1;\n    public static final int TYPE_RESOURCE = 2;\n    public static final int TYPE_DATA     = 3;\n    public static final int TYPE_URI      = 4;\n\n    public static Class<?> TYPE = RefClass.load(Icon.class, android.graphics.drawable.Icon.class);\n    public static RefObject<Object> mObj1;\n    public static RefObject<String> mString1;\n    public static RefObject<Integer> mType;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/hardware/display/DisplayManagerGlobal.java",
    "content": "package mirror.android.hardware.display;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.RefStaticMethod;\n\npublic class DisplayManagerGlobal {\n    public static Class<?> TYPE = RefClass.load(DisplayManagerGlobal.class, \"android.hardware.display.DisplayManagerGlobal\");\n    public static RefStaticMethod<Object> getInstance;\n    public static RefObject<IInterface> mDm;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/hardware/display/IDisplayManager.java",
    "content": "package mirror.android.hardware.display;\n\nimport mirror.RefClass;\n\npublic class IDisplayManager {\n    public static Class<?> TYPE = RefClass.load(IDisplayManager.class, \"android.hardware.display.IDisplayManager\");\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/hardware/fingerprint/IFingerprintService.java",
    "content": "package mirror.android.hardware.fingerprint;\n\nimport android.os.*;\n\nimport mirror.*;\n\n/**\n * Created by natsuki on 12/10/2017.\n */\n\npublic class IFingerprintService {\n\n    public static Class<?> TYPE = RefClass.load(IFingerprintService.class, \"android.hardware.fingerprint.IFingerprintService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.hardware.fingerprint.IFingerprintService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/hardware/location/IContextHubService.java",
    "content": "package mirror.android.hardware.location;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\npublic class IContextHubService {\n    public static Class<?> TYPE = RefClass.load(IContextHubService.class, \"android.hardware.location.IContextHubService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.hardware.location.IContextHubService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/location/ILocationListener.java",
    "content": "package mirror.android.location;\n\nimport android.location.Location;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefStaticMethod;\n\n\n/**\n * @author legency\n */\npublic class ILocationListener {\n    public static Class<?> TYPE = RefClass.load(ILocationListener.class, \"android.location.ILocationListener\");\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.location.ILocationListener$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n    @MethodParams(Location.class)\n    public static RefMethod<Void> onLocationChanged;\n\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/location/ILocationManager.java",
    "content": "package mirror.android.location;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class ILocationManager {\n    public static Class<?> TYPE = RefClass.load(ILocationManager.class, \"android.location.ILocationManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.location.ILocationManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/location/LocationManager.java",
    "content": "package mirror.android.location;\n\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.os.Bundle;\n\nimport java.util.HashMap;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\npublic class LocationManager {\n    public static Class<?> TYPE = RefClass.load(LocationManager.class, \"android.location.LocationManager\");\n    public static RefObject<HashMap> mGnssNmeaListeners;\n    public static RefObject<HashMap> mGnssStatusListeners;\n    public static RefObject<HashMap> mGpsNmeaListeners;\n    public static RefObject<HashMap> mGpsStatusListeners;\n    public static RefObject<HashMap> mListeners;\n    public static RefObject<HashMap> mNmeaListeners;\n\n    public static class GnssStatusListenerTransport {\n        public static Class<?> TYPE = RefClass.load(GnssStatusListenerTransport.class, \"android.location.LocationManager$GnssStatusListenerTransport\");\n        public static RefObject<Object> mGpsListener;\n        public static RefObject<Object> mGpsNmeaListener;\n        @MethodParams({int.class})\n        public static RefMethod<Void> onFirstFix;\n        public static RefMethod<Void> onGnssStarted;\n        @MethodParams({long.class, String.class})\n        public static RefMethod<Void> onNmeaReceived;\n        @MethodParams({int.class, int[].class, float[].class, float[].class, float[].class, float[].class})\n        public static RefMethod<Void> onSvStatusChanged;\n        public static RefObject<Object> this$0;\n    }\n\n    public static class GpsStatusListenerTransport {\n        public static Class<?> TYPE = RefClass.load(GpsStatusListenerTransport.class, \"android.location.LocationManager$GpsStatusListenerTransport\");\n        public static RefObject<Object> mListener;\n        public static RefObject<Object> mNmeaListener;\n        @MethodParams({int.class})\n        public static RefMethod<Void> onFirstFix;\n        public static RefMethod<Void> onGpsStarted;\n        @MethodParams({long.class, String.class})\n        public static RefMethod<Void> onNmeaReceived;\n        @MethodParams({int.class, int[].class, float[].class, float[].class, float[].class, int.class, int.class, int.class})\n        public static RefMethod<Void> onSvStatusChanged;\n        public static RefObject<Object> this$0;\n    }\n\n    public static class GpsStatusListenerTransportOPPO_R815T {\n        public static Class<?> TYPE = RefClass.load(GpsStatusListenerTransportOPPO_R815T.class, \"android.location.LocationManager$GpsStatusListenerTransport\");\n        @MethodParams({int.class, int[].class, float[].class, float[].class, float[].class, int[].class, int[].class, int[].class, int.class})\n        public static RefMethod<Void> onSvStatusChanged;\n    }\n\n    public static class GpsStatusListenerTransportSumsungS5 {\n        public static Class<?> TYPE = RefClass.load(GpsStatusListenerTransportSumsungS5.class, \"android.location.LocationManager$GpsStatusListenerTransport\");\n        @MethodParams({int.class, int[].class, float[].class, float[].class, float[].class, int.class, int.class, int.class, int[].class})\n        public static RefMethod<Void> onSvStatusChanged;\n    }\n\n    public static class GpsStatusListenerTransportVIVO {\n        public static Class<?> TYPE = RefClass.load(GpsStatusListenerTransportVIVO.class, \"android.location.LocationManager$GpsStatusListenerTransport\");\n        @MethodParams({int.class, int[].class, float[].class, float[].class, float[].class, int.class, int.class, int.class, long[].class})\n        public static RefMethod<Void> onSvStatusChanged;\n    }\n\n    public static class ListenerTransport {\n        public static Class<?> TYPE = RefClass.load(ListenerTransport.class, \"android.location.LocationManager$ListenerTransport\");\n        public static RefObject<LocationListener> mListener;\n        @MethodParams({Location.class})\n        public static RefMethod<Void> onLocationChanged;\n        @MethodParams({String.class})\n        public static RefMethod<Void> onProviderDisabled;\n        @MethodParams({String.class})\n        public static RefMethod<Void> onProviderEnabled;\n        @MethodParams({String.class, int.class, Bundle.class})\n        public static RefMethod<Void> onStatusChanged;\n        public static RefObject<Object> this$0;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/location/LocationRequestL.java",
    "content": "package mirror.android.location;\n\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefObject;\n\npublic class LocationRequestL {\n    public static Class<?> TYPE = RefClass.load(LocationRequestL.class, \"android.location.LocationRequest\");\n    public static RefBoolean mHideFromAppOps;\n    public static RefObject<Object> mWorkSource;\n    public static RefObject<String> mProvider;\n    public static RefMethod<String> getProvider;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/media/AudioManager.java",
    "content": "package mirror.android.media;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticMethod;\n\npublic class AudioManager {\n    public static Class<?> TYPE = RefClass.load(AudioManager.class, android.media.AudioManager.class);\n    public static RefStaticMethod getService;\n    public static RefStaticObject<IInterface> sService;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/media/IAudioService.java",
    "content": "package mirror.android.media;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IAudioService {\n    public static Class<?> TYPE = RefClass.load(IAudioService.class, \"android.media.IAudioService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.media.IAudioService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/media/IMediaRouterService.java",
    "content": "package mirror.android.media;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IMediaRouterService {\n    public static Class<?> TYPE = RefClass.load(IMediaRouterService.class, \"android.media.IMediaRouterService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.media.IMediaRouterService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/media/MediaRouter.java",
    "content": "package mirror.android.media;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.RefStaticObject;\n\npublic class MediaRouter {\n    public static Class<?> TYPE = RefClass.load(MediaRouter.class, android.media.MediaRouter.class);\n    public static RefStaticObject sStatic;\n\n    public static class Static {\n        public static Class<?> TYPE = RefClass.load(Static.class, \"android.media.MediaRouter$Static\");\n        public static RefObject<IInterface> mAudioService;\n    }\n\n    public static class StaticKitkat {\n        public static Class<?> TYPE = RefClass.load(StaticKitkat.class, \"android.media.MediaRouter$Static\");\n        public static RefObject<IInterface> mMediaRouterService;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/media/session/ISessionManager.java",
    "content": "package mirror.android.media.session;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class ISessionManager {\n    public static Class<?> TYPE = RefClass.load(ISessionManager.class, \"android.media.session.ISessionManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.media.session.ISessionManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/IConnectivityManager.java",
    "content": "package mirror.android.net;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n\n/**\n * @author Junelegency\n *\n */\npublic class IConnectivityManager {\n    public static Class<?> TYPE = RefClass.load(IConnectivityManager.class, \"android.net.IConnectivityManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.net.IConnectivityManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/NetworkInfo.java",
    "content": "package mirror.android.net;\n\nimport mirror.MethodParams;\nimport mirror.RefBoolean;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class NetworkInfo {\n    public static Class<?> TYPE = RefClass.load(NetworkInfo.class, android.net.NetworkInfo.class);\n    @MethodParams({int.class, int.class, String.class, String.class})\n    public static RefConstructor<android.net.NetworkInfo> ctor;\n    @MethodParams({int.class})\n    public static RefConstructor<android.net.NetworkInfo> ctorOld;\n    public static RefInt mNetworkType;\n    public static RefObject<String> mTypeName;\n    public static RefObject<android.net.NetworkInfo.State> mState;\n    public static RefObject<android.net.NetworkInfo.DetailedState> mDetailedState;\n    public static RefBoolean mIsAvailable;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/wifi/IWifiManager.java",
    "content": "package mirror.android.net.wifi;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IWifiManager {\n    public static Class<?> TYPE = RefClass.load(IWifiManager.class, \"android.net.wifi.IWifiManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.net.wifi.IWifiManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/wifi/WifiInfo.java",
    "content": "package mirror.android.net.wifi;\n\nimport android.net.wifi.SupplicantState;\n\nimport java.net.InetAddress;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\nimport mirror.RefObject;\n\npublic class WifiInfo {\n    public static Class<?> TYPE = RefClass.load(WifiInfo.class, android.net.wifi.WifiInfo.class);\n    public static RefConstructor<android.net.wifi.WifiInfo> ctor;\n    public static RefObject<String> mMacAddress;\n    public static RefInt mNetworkId;\n    public static RefInt mLinkSpeed;\n    public static RefInt mFrequency;\n    public static RefInt mRssi;\n    public static RefObject<SupplicantState> mSupplicantState;\n    public static RefObject<InetAddress> mIpAddress;\n    public static RefObject<Object> mWifiSsid;\n    public static RefObject<String> mBSSID;\n    public static RefObject<String> mSSID;\n\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/wifi/WifiScanner.java",
    "content": "package mirror.android.net.wifi;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic final class WifiScanner {\n    public static Class<?> Class;\n    public static RefStaticObject<String> GET_AVAILABLE_CHANNELS_EXTRA;\n\n    static {\n        RefClass.load(WifiScanner.class, \"android.net.wifi.WifiScanner\");\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/net/wifi/WifiSsid.java",
    "content": "package mirror.android.net.wifi;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\n\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n@TargetApi(Build.VERSION_CODES.KITKAT)\npublic class WifiSsid {\n    public static final Class<?> TYPE = RefClass.load(WifiSsid.class, \"android.net.wifi.WifiSsid\");\n    public static RefStaticMethod<Object> createFromAsciiEncoded;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/BaseBundle.java",
    "content": "package mirror.android.os;\n\nimport android.os.Parcel;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n\npublic class BaseBundle {\n    public static Class<?> TYPE = RefClass.load(BaseBundle.class, \"android.os.BaseBundle\");\n    public static RefObject<Parcel> mParcelledData;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/Build.java",
    "content": "package mirror.android.os;\n\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic class Build {\n    public static Class<?> TYPE = RefClass.load(Build.class, android.os.Build.class);\n    public static RefStaticObject<String> DEVICE;\n    public static RefStaticObject<String> SERIAL;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/Bundle.java",
    "content": "package mirror.android.os;\n\nimport android.os.IBinder;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class Bundle {\n    public static Class<?> TYPE = RefClass.load(Bundle.class, android.os.Bundle.class);\n\n    @MethodParams({String.class, IBinder.class})\n    public static RefMethod<Void> putIBinder;\n\n    @MethodParams({String.class})\n    public static RefMethod<IBinder> getIBinder;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/BundleICS.java",
    "content": "package mirror.android.os;\n\nimport android.os.Parcel;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n\npublic class BundleICS {\n    public static Class<?> TYPE = RefClass.load(BundleICS.class, \"android.os.Bundle\");\n    public static RefObject<Parcel> mParcelledData;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/Handler.java",
    "content": "package mirror.android.os;\n\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class Handler {\n    public static Class<?> TYPE = RefClass.load(Handler.class, \"android.os.Handler\");\n    public static RefObject<android.os.Handler.Callback> mCallback;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/IDeviceIdentifiersPolicyService.java",
    "content": "package mirror.android.os;\n\nimport android.annotation.TargetApi;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author weishu\n * @date 2021/8/19.\n */\n@TargetApi(29)\npublic class IDeviceIdentifiersPolicyService {\n    public static Class<?> TYPE = RefClass.load(IDeviceIdentifiersPolicyService.class, \"android.os.IDeviceIdentifiersPolicyService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(IDeviceIdentifiersPolicyService.Stub.class, \"android.os.IDeviceIdentifiersPolicyService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/INetworkManagementService.java",
    "content": "package mirror.android.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class INetworkManagementService {\n    public static Class<?> TYPE = RefClass.load(INetworkManagementService.class, \"android.os.INetworkManagementService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.INetworkManagementService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/IPowerManager.java",
    "content": "package mirror.android.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class IPowerManager {\n    public static Class<?> TYPE = RefClass.load(IPowerManager.class, \"android.os.IPowerManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.IPowerManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/IUserManager.java",
    "content": "package mirror.android.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IUserManager {\n    public static Class<?> TYPE = RefClass.load(IUserManager.class, \"android.os.IUserManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.IUserManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/Message.java",
    "content": "package mirror.android.os;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.RefStaticMethod;\n\npublic class Message {\n    public static Class<?> TYPE = RefClass.load(Message.class, android.os.Message.class);\n    @MethodParams({int.class})\n    public static RefStaticMethod<Void> updateCheckRecycle;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/Process.java",
    "content": "package mirror.android.os;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class Process {\n    public static Class<?> TYPE = RefClass.load(Process.class, android.os.Process.class);\n    @MethodParams({String.class})\n    public static RefStaticMethod<Void> setArgV0;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/ServiceManager.java",
    "content": "package mirror.android.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.util.Map;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticObject;\nimport mirror.RefStaticMethod;\n\npublic class ServiceManager {\n    public static Class<?> TYPE = RefClass.load(ServiceManager.class, \"android.os.ServiceManager\");\n    @MethodParams({String.class, IBinder.class})\n    public static RefStaticMethod<Void> addService;\n    public static RefStaticMethod<IBinder> checkService;\n    public static RefStaticMethod<IInterface> getIServiceManager;\n    public static RefStaticMethod<IBinder> getService;\n    public static RefStaticMethod<String[]> listServices;\n    public static RefStaticObject<Map<String, IBinder>> sCache;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/StrictMode.java",
    "content": "package mirror.android.os;\n\n\nimport mirror.RefClass;\nimport mirror.RefStaticInt;\n\npublic class StrictMode {\n    public static Class<?> TYPE = RefClass.load(StrictMode.class, \"android.os.StrictMode\");\n    public static RefStaticInt sVmPolicyMask;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/UserHandle.java",
    "content": "package mirror.android.os;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefMethod;\n\n/**\n * author: weishu on 18/2/11.\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class UserHandle {\n    public static Class<?> TYPE = RefClass.load(UserHandle.class, android.os.UserHandle.class);\n    @MethodParams({int.class})\n    public static RefConstructor<android.os.UserHandle> ctor;\n    public static RefMethod<Integer> getIdentifier;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/mount/IMountService.java",
    "content": "package mirror.android.os.mount;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IMountService {\n    public static Class<?> TYPE = RefClass.load(IMountService.class, \"android.os.storage.IMountService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.storage.IMountService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/os/storage/IStorageManager.java",
    "content": "package mirror.android.os.storage;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class IStorageManager {\n    public static Class<?> Class = RefClass.load(IStorageManager.class, \"android.os.storage.IStorageManager\");\n\n    public static class Stub {\n        public static Class<?> Class = RefClass.load(Stub.class, \"android.os.storage.IStorageManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/providers/Settings.java",
    "content": "package mirror.android.providers;\n\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\npublic class Settings {\n    public static Class<?> TYPE = RefClass.load(Settings.class, android.provider.Settings.class);\n\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\n    public static class Global {\n        public static Class<?> TYPE = RefClass.load(Global.class, android.provider.Settings.Global.class);\n        public static RefStaticObject<Object> sNameValueCache;\n    }\n\n    public static class NameValueCache {\n        public static Class<?> TYPE = RefClass.load(NameValueCache.class, \"android.provider.Settings$NameValueCache\");\n        public static RefObject<Object> mContentProvider;\n    }\n\n    public static class NameValueCacheOreo {\n        public static Class<?> TYPE = RefClass.load(NameValueCacheOreo.class, \"android.provider.Settings$NameValueCache\");\n        public static RefObject<Object> mProviderHolder;\n    }\n\n    public static class ContentProviderHolder {\n        public static Class<?> TYPE = RefClass.load(ContentProviderHolder.class, \"android.provider.Settings$ContentProviderHolder\");\n        public static RefObject<IInterface> mContentProvider;\n    }\n\n    public static class Secure {\n        public static Class<?> TYPE = RefClass.load(Secure.class, android.provider.Settings.Secure.class);\n        public static RefStaticObject<Object> sNameValueCache;\n    }\n\n    public static class System {\n        public static Class<?> TYPE = RefClass.load(System.class, android.provider.Settings.System.class);\n        public static RefStaticObject<Object> sNameValueCache;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/renderscript/RenderScriptCacheDir.java",
    "content": "package mirror.android.renderscript;\n\n\nimport java.io.File;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class RenderScriptCacheDir {\n    public static Class<?> TYPE = RefClass.load(RenderScriptCacheDir.class, \"android.renderscript.RenderScriptCacheDir\");\n    @MethodParams({File.class})\n    public static RefStaticMethod<Void> setupDiskCache;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/rms/resource/ReceiverResourceLP.java",
    "content": "package mirror.android.rms.resource;\n\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ReceiverResourceLP {\n    public static Class<?> TYPE = RefClass.load(ReceiverResourceLP.class, \"android.rms.resource.ReceiverResource\");\n    public static RefObject<Object> mResourceConfig;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/rms/resource/ReceiverResourceM.java",
    "content": "package mirror.android.rms.resource;\n\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ReceiverResourceM {\n    public static Class<?> TYPE = RefClass.load(ReceiverResourceM.class, \"android.rms.resource.ReceiverResource\");\n    public static RefObject<String[]> mWhiteList;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/rms/resource/ReceiverResourceN.java",
    "content": "package mirror.android.rms.resource;\n\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class ReceiverResourceN {\n    public static Class<?> TYPE = RefClass.load(ReceiverResourceN.class, \"android.rms.resource.ReceiverResource\");\n    public static RefObject<List<String>> mWhiteList;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/service/persistentdata/IPersistentDataBlockService.java",
    "content": "package mirror.android.service.persistentdata;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IPersistentDataBlockService {\n    public static Class<?> TYPE = RefClass.load(IPersistentDataBlockService.class, \"android.service.persistentdata.IPersistentDataBlockService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.service.persistentdata.IPersistentDataBlockService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellIdentityCdma.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellIdentityCdma {\n    public static Class<?> TYPE = RefClass.load(CellIdentityCdma.class, android.telephony.CellIdentityCdma.class);\n    public static RefConstructor<android.telephony.CellIdentityCdma> ctor;\n    public static RefInt mNetworkId;\n    public static RefInt mSystemId;\n    public static RefInt mBasestationId;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellIdentityGsm.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellIdentityGsm {\n    public static Class<?> TYPE = RefClass.load(CellIdentityGsm.class, android.telephony.CellIdentityGsm.class);\n    public static RefConstructor<android.telephony.CellIdentityGsm> ctor;\n    public static RefInt mMcc;\n    public static RefInt mMnc;\n    public static RefInt mLac;\n    public static RefInt mCid;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellInfoCdma.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.telephony.CellSignalStrengthCdma;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellInfoCdma {\n    public static Class<?> TYPE = RefClass.load(CellInfoCdma.class, android.telephony.CellInfoCdma.class);\n    public static RefConstructor<android.telephony.CellInfoCdma> ctor;\n    public static RefObject<android.telephony.CellIdentityCdma> mCellIdentityCdma;\n    public static RefObject<CellSignalStrengthCdma> mCellSignalStrengthCdma;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellInfoGsm.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellInfoGsm {\n    public static Class<?> TYPE = RefClass.load(CellInfoGsm.class, android.telephony.CellInfoGsm.class);\n    public static RefConstructor<android.telephony.CellInfoGsm> ctor;\n    public static RefObject<android.telephony.CellIdentityGsm> mCellIdentityGsm;\n    public static RefObject<android.telephony.CellSignalStrengthGsm> mCellSignalStrengthGsm;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellSignalStrengthCdma.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellSignalStrengthCdma {\n    public static Class<?> TYPE = RefClass.load(CellSignalStrengthCdma.class, android.telephony.CellSignalStrengthCdma.class);\n    public static RefConstructor<android.telephony.CellSignalStrengthCdma> ctor;\n    public static RefInt mCdmaDbm;\n    public static RefInt mCdmaEcio;\n    public static RefInt mEvdoDbm;\n    public static RefInt mEvdoEcio;\n    public static RefInt mEvdoSnr;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/CellSignalStrengthGsm.java",
    "content": "package mirror.android.telephony;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.RefInt;\n\n/**\n * @author Lody\n */\n\n@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)\npublic class CellSignalStrengthGsm {\n    public static Class<?> TYPE = RefClass.load(CellSignalStrengthGsm.class, android.telephony.CellSignalStrengthGsm.class);\n    public static RefConstructor<android.telephony.CellSignalStrengthGsm> ctor;\n    public static RefInt mSignalStrength;\n    public static RefInt mBitErrorRate;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/telephony/NeighboringCellInfo.java",
    "content": "package mirror.android.telephony;\n\nimport mirror.RefClass;\nimport mirror.RefInt;\n\n/**\n * @author Lody\n */\n\npublic class NeighboringCellInfo {\n    public static Class<?> TYPE = RefClass.load(NeighboringCellInfo.class, android.telephony.NeighboringCellInfo.class);\n    public static RefInt mLac;\n    public static RefInt mCid;\n    public static RefInt mRssi;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/util/Singleton.java",
    "content": "package mirror.android.util;\n\n\nimport mirror.RefClass;\nimport mirror.RefObject;\nimport mirror.RefMethod;\n\npublic class Singleton {\n    public static Class<?> TYPE = RefClass.load(Singleton.class, \"android.util.Singleton\");\n    public static RefMethod<Object> get;\n    public static RefObject<Object> mInstance;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/Display.java",
    "content": "package mirror.android.view;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic class Display {\n    public static Class<?> TYPE = RefClass.load(Display.class, android.view.Display.class);\n    public static RefStaticObject<IInterface> sWindowManager;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/HardwareRenderer.java",
    "content": "package mirror.android.view;\n\n\nimport java.io.File;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class HardwareRenderer {\n    public static Class<?> TYPE = RefClass.load(HardwareRenderer.class, \"android.view.HardwareRenderer\");\n    @MethodParams({File.class})\n    public static RefStaticMethod<Void> setupDiskCache;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/IAutoFillManager.java",
    "content": "package mirror.android.view;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class IAutoFillManager {\n\n    public static Class<?> TYPE = RefClass.load(IAutoFillManager.class,\n            \"android.view.autofill.IAutoFillManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class,\n                \"android.view.autofill.IAutoFillManager$Stub\");\n        @MethodParams(IBinder.class)\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/IGraphicsStats.java",
    "content": "package mirror.android.view;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IGraphicsStats {\n    public static Class<?> TYPE = RefClass.load(IGraphicsStats.class, \"android.view.IGraphicsStats\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.view.IGraphicsStats$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/IWindowManager.java",
    "content": "package mirror.android.view;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IWindowManager {\n    public static Class<?> TYPE = RefClass.load(IWindowManager.class, \"android.view.IWindowManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.view.IWindowManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/RenderScript.java",
    "content": "package mirror.android.view;\n\nimport java.io.File;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class RenderScript {\n    public static Class<?> TYPE = RefClass.load(RenderScript.class, android.renderscript.RenderScript.class);\n    @MethodParams({File.class})\n    public static RefStaticMethod<Void> setupDiskCache;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/SurfaceControl.java",
    "content": "package mirror.android.view;\n\nimport android.graphics.Bitmap;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class SurfaceControl {\n\n    public static Class<?> TYPE = RefClass.load(SurfaceControl.class, \"android.view.SurfaceControl\");\n\n    @MethodParams({int.class/*width*/, int.class/*height*/})\n    public static RefStaticMethod<Bitmap> screnshot;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/ThreadedRenderer.java",
    "content": "package mirror.android.view;\n\n\nimport java.io.File;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class ThreadedRenderer {\n    public static Class<?> TYPE = RefClass.load(ThreadedRenderer.class, \"android.view.ThreadedRenderer\");\n    @MethodParams({File.class})\n    public static RefStaticMethod<Void> setupDiskCache;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/view/WindowManagerGlobal.java",
    "content": "package mirror.android.view;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic class WindowManagerGlobal {\n    public static Class<?> TYPE = RefClass.load(WindowManagerGlobal.class, \"android.view.WindowManagerGlobal\");\n    public static RefStaticObject<IInterface> sWindowManagerService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/webkit/IWebViewUpdateService.java",
    "content": "package mirror.android.webkit;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\n\n/**\n * @author CodeHz\n */\n\npublic class IWebViewUpdateService {\n    public static Class<?> TYPE = RefClass.load(IWebViewUpdateService.class, \"android.webkit.IWebViewUpdateService$Stub$Proxy\");\n\n    public static RefMethod<String> getCurrentWebViewPackageName;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/webkit/WebViewFactory.java",
    "content": "package mirror.android.webkit;\n\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author CodeHz\n */\n\npublic class WebViewFactory {\n\tpublic static Class<?> TYPE = RefClass.load(WebViewFactory.class, \"android.webkit.WebViewFactory\");\n\tpublic static RefStaticMethod<Object> getUpdateService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/widget/RemoteViews.java",
    "content": "package mirror.android.widget;\n\nimport android.content.pm.ApplicationInfo;\n\nimport java.util.ArrayList;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class RemoteViews {\n    public static Class<?> TYPE = RefClass.load(RemoteViews.class, android.widget.RemoteViews.class);\n    public static RefObject<ApplicationInfo> mApplication;\n    public static RefObject<ArrayList<Object>> mActions;\n    public static RefObject<String> mPackage;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/android/widget/Toast.java",
    "content": "package mirror.android.widget;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic class Toast {\n    public static Class<?> TYPE = RefClass.load(Toast.class, android.widget.Toast.class);\n\n    public static RefStaticObject<IInterface> sService;\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/R_Hide.java",
    "content": "package mirror.com.android.internal;\n\nimport mirror.RefClass;\nimport mirror.RefStaticInt;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic final class R_Hide {\n\n    public static Class<?> TYPE = RefClass.load(R_Hide.class, \"com.android.internal.R\");\n\n    public static class id {\n        public static Class<?> TYPE = RefClass.load(id.class, \"com.android.internal.R$id\");\n        public static RefStaticInt icon;\n        public static RefStaticInt contentPanel;\n        public static RefStaticInt topPanel;\n        public static RefStaticInt buttonPanel;\n        public static RefStaticInt customPanel;\n        public static RefStaticInt custom;\n        public static RefStaticInt titleDivider;\n        public static RefStaticInt titleDividerTop;\n        public static RefStaticInt title_template;\n        public static RefStaticInt scrollView;\n        public static RefStaticInt alertTitle;\n        public static RefStaticInt message;\n        public static RefStaticInt button1;\n        public static RefStaticInt button2;\n        public static RefStaticInt button3;\n        public static RefStaticInt text1;\n        public static RefStaticInt text2;\n        public static RefStaticInt leftSpacer;\n        public static RefStaticInt rightSpacer;\n        public static RefStaticInt resolver_list;\n    }\n\n    public static class layout {\n        public static Class<?> TYPE = RefClass.load(id.class, \"com.android.internal.R$layout\");\n        public static RefStaticInt resolver_list;\n    }\n\n    public static class drawable {\n        public static Class<?> TYPE = RefClass.load(id.class, \"com.android.internal.R$drawable\");\n        public static RefStaticInt popup_full_dark;\n        public static RefStaticInt popup_top_dark;\n        public static RefStaticInt popup_bottom_dark;\n        public static RefStaticInt popup_full_bright;\n        public static RefStaticInt popup_top_bright;\n        public static RefStaticInt popup_center_bright;\n        public static RefStaticInt popup_bottom_bright;\n        public static RefStaticInt popup_bottom_medium;\n        public static RefStaticInt popup_center_dark;\n    }\n\n    public static class styleable {\n\n        public static Class<?> TYPE = RefClass.load(styleable.class, \"com.android.internal.R$styleable\");\n\n        public static RefStaticObject<int[]> AccountAuthenticator;\n        public static RefStaticInt AccountAuthenticator_accountPreferences;\n        public static RefStaticInt AccountAuthenticator_accountType;\n        public static RefStaticInt AccountAuthenticator_customTokens;\n        public static RefStaticInt AccountAuthenticator_icon;\n        public static RefStaticInt AccountAuthenticator_label;\n        public static RefStaticInt AccountAuthenticator_smallIcon;\n        public static RefStaticObject<int[]> SyncAdapter;\n        public static RefStaticInt SyncAdapter_accountType;\n        public static RefStaticInt SyncAdapter_allowParallelSyncs;\n        public static RefStaticInt SyncAdapter_contentAuthority;\n        public static RefStaticInt SyncAdapter_isAlwaysSyncable;\n        public static RefStaticInt SyncAdapter_settingsActivity;\n        public static RefStaticInt SyncAdapter_supportsUploading;\n        public static RefStaticInt SyncAdapter_userVisible;\n        public static RefStaticObject<int[]> Window;\n        public static RefStaticInt Window_windowBackground;\n        public static RefStaticInt Window_windowFullscreen;\n        public static RefStaticInt Window_windowIsFloating;\n        public static RefStaticInt Window_windowIsTranslucent;\n        public static RefStaticInt Window_windowShowWallpaper;\n        public static RefStaticInt AlertDialog_fullDark;\n        public static RefStaticInt AlertDialog_topDark;\n        public static RefStaticInt AlertDialog_centerDark;\n        public static RefStaticInt AlertDialog_bottomDark;\n        public static RefStaticInt AlertDialog_fullBright;\n        public static RefStaticInt AlertDialog_topBright;\n        public static RefStaticInt AlertDialog_centerBright;\n        public static RefStaticInt AlertDialog_bottomBright;\n        public static RefStaticInt AlertDialog_bottomMedium;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/app/IAppOpsService.java",
    "content": "package mirror.com.android.internal.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IAppOpsService {\n    public static Class<?> TYPE = RefClass.load(IAppOpsService.class, \"com.android.internal.app.IAppOpsService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.app.IAppOpsService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/app/IBatteryStats.java",
    "content": "package mirror.com.android.internal.app;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\n/**\n * @author weishu\n * @date 2020/11/24.\n */\n\npublic class IBatteryStats {\n    public static Class<?> TYPE = RefClass.load(IBatteryStats.class, \"com.android.internal.app.IBatteryStats\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(IBatteryStats.Stub.class, \"com.android.internal.app.IBatteryStats$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/appwidget/IAppWidgetService.java",
    "content": "package mirror.com.android.internal.appwidget;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IAppWidgetService {\n    public static Class<?> TYPE = RefClass.load(IAppWidgetService.class, \"com.android.internal.appwidget.IAppWidgetService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.appwidget.IAppWidgetService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/content/NativeLibraryHelper.java",
    "content": "package mirror.com.android.internal.content;\n\nimport java.io.File;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class NativeLibraryHelper {\n    public static Class<?> TYPE = RefClass.load(NativeLibraryHelper.class, \"com.android.internal.content.NativeLibraryHelper\");\n\n    @MethodParams({Handle.class, File.class, String.class})\n    public static RefStaticMethod<Integer> copyNativeBinaries;\n\n    @MethodParams({Handle.class, String[].class})\n    public static RefStaticMethod<Integer> findSupportedAbi;\n\n    public static class Handle {\n        public static Class<?> TYPE = RefClass.load(Handle.class, \"com.android.internal.content.NativeLibraryHelper$Handle\");\n\n        @MethodParams({File.class})\n        public static RefStaticMethod<Object> create;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/content/ReferrerIntent.java",
    "content": "package mirror.com.android.internal.content;\n\nimport android.content.Intent;\n\nimport mirror.RefClass;\nimport mirror.RefConstructor;\nimport mirror.MethodParams;\n\n/**\n * @author Lody\n */\n\npublic class ReferrerIntent {\n    public static Class<?> TYPE = RefClass.load(ReferrerIntent.class, \"com.android.internal.content.ReferrerIntent\");\n    @MethodParams({Intent.class, String.class})\n    public static RefConstructor<Intent> ctor;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/os/IDropBoxManagerService.java",
    "content": "package mirror.com.android.internal.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IDropBoxManagerService {\n    public static Class<?> TYPE = RefClass.load(IDropBoxManagerService.class, \"com.android.internal.os.IDropBoxManagerService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.os.IDropBoxManagerService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/os/IVibratorService.java",
    "content": "package mirror.com.android.internal.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IVibratorService {\n    public static Class<?> TYPE = RefClass.load(IVibratorService.class, \"android.os.IVibratorService\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.IVibratorService$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/os/UserManager.java",
    "content": "package mirror.com.android.internal.os;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class UserManager {\n    public static Class<?> TYPE = RefClass.load(UserManager.class, \"android.os.UserManager\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"android.os.IUserManager$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/os/health/SystemHealthManager.java",
    "content": "package mirror.com.android.internal.os.health;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author weishu\n * @date 2020/11/24.\n */\n\npublic class SystemHealthManager {\n    public static Class<?> TYPE = RefClass.load(SystemHealthManager.class, \"android.os.health.SystemHealthManager\");\n\n    public static RefObject<IInterface> mBatteryStats;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/policy/PhoneWindow.java",
    "content": "package mirror.com.android.internal.policy;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\npublic class PhoneWindow {\n    public static Class<?> TYPE;\n    public static RefStaticObject<IInterface> sWindowManager;\n\n    static {\n        TYPE = RefClass.load(PhoneWindow.class, \"com.android.internal.policy.impl.PhoneWindow$WindowManagerHolder\");\n        if (TYPE == null) {\n            TYPE = RefClass.load(PhoneWindow.class, \"com.android.internal.policy.PhoneWindow$WindowManagerHolder\");\n        }\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/IMms.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IMms {\n    public static Class<?> TYPE = RefClass.load(IMms.class, \"com.android.internal.telephony.IMms\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.telephony.IMms$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/IPhoneSubInfo.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class IPhoneSubInfo {\n    public static Class<?> TYPE = RefClass.load(IPhoneSubInfo.class, \"com.android.internal.telephony.IPhoneSubInfo\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.telephony.IPhoneSubInfo$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/ISms.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class ISms {\n    public static Class<?> TYPE = RefClass.load(ISms.class, \"com.android.internal.telephony.ISms\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.telephony.ISms$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/ISub.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class ISub {\n    public static Class<?> TYPE = RefClass.load(ISub.class, \"com.android.internal.telephony.ISub\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.telephony.ISub$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/ITelephony.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\npublic class ITelephony {\n    public static Class<?> TYPE = RefClass.load(ITelephony.class, \"com.android.internal.telephony.ITelephony\");\n\n    public static class Stub {\n        public static Class<?> TYPE = RefClass.load(Stub.class, \"com.android.internal.telephony.ITelephony$Stub\");\n        @MethodParams({IBinder.class})\n        public static RefStaticMethod<IInterface> asInterface;\n    }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/ITelephonyRegistry.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport mirror.MethodParams;\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class ITelephonyRegistry {\n\tpublic static Class<?> TYPE = RefClass.load(ITelephonyRegistry.class, \"com.android.internal.telephony.ITelephonyRegistry\");\n\n\tpublic static class Stub {\n\t\tpublic static Class<?> TYPE = RefClass.load(ITelephonyRegistry.Stub.class, \"com.android.internal.telephony.ITelephonyRegistry$Stub\");\n\t\t@MethodParams({IBinder.class})\n\t\tpublic static RefStaticMethod<IInterface> asInterface;\n\t}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/telephony/PhoneConstantsMtk.java",
    "content": "package mirror.com.android.internal.telephony;\n\nimport mirror.RefClass;\nimport mirror.RefStaticInt;\n\npublic class PhoneConstantsMtk {\n    public static Class<?> TYPE = RefClass.load(PhoneConstantsMtk.class, \"com.android.internal.telephony.PhoneConstants\");\n    public static RefStaticInt GEMINI_SIM_NUM;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/view/IInputMethodManager.java",
    "content": "package mirror.com.android.internal.view;\n\nimport mirror.RefClass;\n\npublic class IInputMethodManager {\n    public static Class<?> TYPE = RefClass.load(IInputMethodManager.class, \"com.android.internal.view.IInputMethodManager\");\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/com/android/internal/view/inputmethod/InputMethodManager.java",
    "content": "package mirror.com.android.internal.view.inputmethod;\n\nimport android.os.IInterface;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\npublic class InputMethodManager {\n    public static Class<?> TYPE = RefClass.load(InputMethodManager.class, android.view.inputmethod.InputMethodManager.class);\n    public static RefObject<IInterface> mService;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/dalvik/system/VMRuntime.java",
    "content": "package mirror.dalvik.system;\n\nimport mirror.RefClass;\nimport mirror.RefMethod;\nimport mirror.MethodParams;\nimport mirror.RefStaticMethod;\n\n/**\n * @author Lody\n */\n\npublic class VMRuntime {\n        public static Class<?> TYPE = RefClass.load(VMRuntime.class, \"dalvik.system.VMRuntime\");\n        public static RefStaticMethod<Object> getRuntime;\n        @MethodParams({int.class})\n        public static RefMethod<Void> setTargetSdkVersion;\n        public static RefMethod<Boolean> is64Bit;\n        public static RefStaticMethod<String> getCurrentInstructionSet;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/java/lang/ThreadGroup.java",
    "content": "package mirror.java.lang;\n\n\nimport java.util.List;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\npublic class ThreadGroup {\n    public static Class<?> TYPE = RefClass.load(ThreadGroup.class, java.lang.ThreadGroup.class);\n    public static RefObject<List<java.lang.ThreadGroup>> groups;\n    public static RefObject<java.lang.ThreadGroup> parent;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/java/lang/ThreadGroupN.java",
    "content": "package mirror.java.lang;\n\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\npublic class ThreadGroupN {\n    public static Class<?> Class = RefClass.load(ThreadGroupN.class, java.lang.ThreadGroup.class);\n    public static RefObject<Integer> ngroups;\n    public static RefObject<java.lang.ThreadGroup[]> groups;\n    public static RefObject<java.lang.ThreadGroup> parent;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/libcore/io/ForwardingOs.java",
    "content": "package mirror.libcore.io;\n\nimport mirror.RefClass;\nimport mirror.RefObject;\n\n/**\n * @author Lody\n */\n\npublic class ForwardingOs {\n    public static Class<?> TYPE = RefClass.load(ForwardingOs.class, \"libcore.io.ForwardingOs\");\n    public static RefObject<Object> os;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/libcore/io/Libcore.java",
    "content": "package mirror.libcore.io;\n\nimport mirror.RefClass;\nimport mirror.RefStaticObject;\n\n/**\n * @author Lody\n */\n\npublic class Libcore {\n    public static Class<?> TYPE = RefClass.load(Libcore.class, \"libcore.io.Libcore\");\n\n    public static RefStaticObject<Object> os;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/libcore/io/Os.java",
    "content": "package mirror.libcore.io;\n\nimport mirror.RefClass;\n\n/**\n * @author Lody\n */\n\npublic class Os {\n    public static Class<?> TYPE = RefClass.load(Os.class, \"libcore.io.Os\");\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/java/mirror/mirror/android/security/net/config/ApplicationConfig.java",
    "content": "package mirror.android.security.net.config;\n\nimport mirror.RefClass;\nimport mirror.RefStaticMethod;\n\npublic class ApplicationConfig {\n    public static Class<?> TYPE = RefClass.load(ApplicationConfig.class, \"android.security.net.config.ApplicationConfig\");\n\n    public static RefStaticMethod setDefaultInstance;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/A64Inlinehook/And64InlineHook.cpp",
    "content": "/*\n *  @date   : 2018/04/18\n *  @author : Rprop (r_prop@outlook.com)\n *  https://github.com/Rprop/And64InlineHook\n */\n/*\n MIT License\n\n Copyright (c) 2018 Rprop (r_prop@outlook.com)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n#define  __STDC_FORMAT_MACROS\n\n#if defined(__aarch64__)\n\n#include <string.h>\n#include <stdlib.h>\n#include <sys/mman.h>\n#include \"And64InlineHook.hpp\"\n#define   A64_MAX_INSTRUCTIONS 5\n#define   A64_MAX_REFERENCES   (A64_MAX_INSTRUCTIONS * 2)\n#define   A64_NOP              0xd503201fu\n#define   A64_JNIEXPORT        __attribute__((visibility(\"default\")))\n#define __flush_cache(c, n)        __builtin___clear_cache(reinterpret_cast<char *>(c), reinterpret_cast<char *>(c) + n)\n\n\ntypedef uint32_t *__restrict *__restrict instruction;\ntypedef struct\n{\n    struct fix_info\n    {\n        uint32_t *bp;\n        uint32_t  ls; // left-shift counts\n        uint32_t  ad; // & operand\n    };\n    struct insns_info\n    {\n        union\n        {\n            uint64_t insu;\n            int64_t  ins;\n            void    *insp;\n        };\n        fix_info fmap[A64_MAX_REFERENCES];\n    };\n    int64_t    basep;\n    int64_t    endp;\n    insns_info dat[A64_MAX_INSTRUCTIONS];\n\npublic:\n    inline bool is_in_fixing_range(const int64_t absolute_addr) {\n        return absolute_addr >= this->basep && absolute_addr < this->endp;\n    }\n    inline intptr_t get_ref_ins_index(const int64_t absolute_addr) {\n        return static_cast<intptr_t>((absolute_addr - this->basep) / sizeof(uint32_t));\n    }\n    inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) {\n        intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast<int64_t>(inp));\n        this->dat[current_idx].insp = outp;\n        return current_idx;\n    }\n    inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) {\n        this->dat[idx].insp = outp;\n    }\n    void insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) {\n        for (auto &f : this->dat[idx].fmap) {\n            if (f.bp == NULL) {\n                f.bp = bp;\n                f.ls = ls;\n                f.ad = ad;\n                return;\n            } //if\n        }\n        // What? GGing..\n    }\n    void process_fix_map(const intptr_t idx) {\n        for (auto &f : this->dat[idx].fmap) {\n            if (f.bp == NULL) break;\n            *(f.bp) = *(f.bp) | (((int32_t(this->dat[idx].ins - reinterpret_cast<int64_t>(f.bp)) >> 2) << f.ls) & f.ad);\n            f.bp = NULL;\n        }\n    }\n} context;\n\n//-------------------------------------------------------------------------\n\nstatic bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp)\n{\n    static constexpr uint32_t mbits = 6u;\n    static constexpr uint32_t mask  = 0xfc000000u; // 0b11111100000000000000000000000000\n    static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111\n    static constexpr uint32_t op_b  = 0x14000000u; // \"b\"  ADDR_PCREL26\n    static constexpr uint32_t op_bl = 0x94000000u; // \"bl\" ADDR_PCREL26\n\n    const uint32_t ins = *(*inpp);\n    const uint32_t opc = ins & mask;\n    switch (opc) {\n        case op_b:\n        case op_bl:\n        {\n            intptr_t current_idx  = ctxp->get_and_set_current_index(*inpp, *outpp);\n            int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + (static_cast<int32_t>(ins << mbits) >> (mbits - 2u)); // sign-extended\n            int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted\n            bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr);\n            // whether the branch should be converted to absolute jump\n            if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) {\n                bool b_aligned = (reinterpret_cast<uint64_t>(*outpp + 2) & 7u) == 0u;\n                if (opc == op_b) {\n                    if (b_aligned != true) {\n                        (*outpp)[0] = A64_NOP;\n                        ctxp->reset_current_ins(current_idx, ++(*outpp));\n                    } //if\n                    (*outpp)[0] = 0x58000051u; // LDR X17, #0x8\n                    (*outpp)[1] = 0xd61f0220u; // BR X17\n                    memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr));\n                    *outpp += 4;\n                } else {\n                    if (b_aligned == true) {\n                        (*outpp)[0] = A64_NOP;\n                        ctxp->reset_current_ins(current_idx, ++(*outpp));\n                    } //if\n                    (*outpp)[0] = 0x58000071u; // LDR X17, #12\n                    (*outpp)[1] = 0x1000009eu; // ADR X30, #16\n                    (*outpp)[2] = 0xd61f0220u; // BR X17\n                    memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr));\n                    *outpp += 5;\n                } //if\n            } else {\n                if (special_fix_type) {\n                    intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr);\n                    if (ref_idx <= current_idx) {\n                        new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp)) >> 2;\n                    } else {\n                        ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask);\n                        new_pc_offset = 0;\n                    } //if\n                } //if\n\n                (*outpp)[0] = opc | (new_pc_offset & ~mask);\n                ++(*outpp);\n            } //if\n\n            ++(*inpp);\n            return ctxp->process_fix_map(current_idx), true;\n        }\n    }\n    return false;\n}\n\n//-------------------------------------------------------------------------\n\nstatic bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp)\n{\n    static constexpr uint32_t lsb     = 5u;\n    static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111\n    static constexpr uint32_t mask0   = 0xff000010u; // 0b11111111000000000000000000010000\n    static constexpr uint32_t op_bc   = 0x54000000u; // \"b.c\"  ADDR_PCREL19\n    static constexpr uint32_t mask1   = 0x7f000000u; // 0b01111111000000000000000000000000\n    static constexpr uint32_t op_cbz  = 0x34000000u; // \"cbz\"  Rt, ADDR_PCREL19\n    static constexpr uint32_t op_cbnz = 0x35000000u; // \"cbnz\" Rt, ADDR_PCREL19\n    static constexpr uint32_t lmask2  = 0xfff8001fu; // 0b11111111111110000000000000011111\n    static constexpr uint32_t mask2   = 0x7f000000u; // 0b01111111000000000000000000000000\n    static constexpr uint32_t op_tbz  = 0x36000000u; // 0b00110110000000000000000000000000 \"tbz\"  Rt, BIT_NUM, ADDR_PCREL14\n    static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 \"tbnz\" Rt, BIT_NUM, ADDR_PCREL14\n\n    const uint32_t ins = *(*inpp);\n    uint32_t     lmask = lmask01;\n    if ((ins & mask0) != op_bc) {\n        uint32_t opc   = ins & mask1;\n        if (opc != op_cbz && opc != op_cbnz) {\n            opc = ins & mask2;\n            if (opc != op_tbz && opc != op_tbnz) {\n                return false;\n            } //if\n            lmask = lmask2;\n        } //if\n    } //if\n\n    intptr_t current_idx  = ctxp->get_and_set_current_index(*inpp, *outpp);\n    int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + ((ins & ~lmask) >> (lsb - 2u));\n    int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted\n    bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr);\n    if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) {\n        if ((reinterpret_cast<uint64_t>(*outpp + 4) & 7u) != 0u) {\n            (*outpp)[0] = A64_NOP;\n            ctxp->reset_current_ins(current_idx, ++(*outpp));\n        } //if\n        (*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8\n        (*outpp)[1] = 0x14000005u; // B #0x14\n        (*outpp)[2] = 0x58000051u; // LDR X17, #0x8\n        (*outpp)[3] = 0xd61f0220u; // BR X17\n        memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr));\n        *outpp += 6;\n    } else {\n        if (special_fix_type) {\n            intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr);\n            if (ref_idx <= current_idx) {\n                new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp)) >> 2;\n            } else {\n                ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask);\n                new_pc_offset = 0;\n            } //if\n        } //if\n\n        (*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << lsb) & ~lmask) | (ins & lmask);\n        ++(*outpp);\n    } //if\n\n    ++(*inpp);\n    return ctxp->process_fix_map(current_idx), true;\n}\n\n//-------------------------------------------------------------------------\n\nstatic bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp)\n{\n    const uint32_t ins = *(*inpp);\n\n    // memory prefetch(\"prfm\"), just skip it\n    // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html\n    if ((ins & 0xff000000u) == 0xd8000000u) {\n        ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp));\n        ++(*inpp);\n        return true;\n    } //if\n\n    static constexpr uint32_t msb        = 8u;\n    static constexpr uint32_t lsb        = 5u;\n    static constexpr uint32_t mask_30    = 0x40000000u; // 0b01000000000000000000000000000000\n    static constexpr uint32_t mask_31    = 0x80000000u; // 0b10000000000000000000000000000000\n    static constexpr uint32_t lmask      = 0xff00001fu; // 0b11111111000000000000000000011111\n    static constexpr uint32_t mask_ldr   = 0xbf000000u; // 0b10111111000000000000000000000000\n    static constexpr uint32_t op_ldr     = 0x18000000u; // 0b00011000000000000000000000000000 \"LDR Wt/Xt, label\" | ADDR_PCREL19\n    static constexpr uint32_t mask_ldrv  = 0x3f000000u; // 0b00111111000000000000000000000000\n    static constexpr uint32_t op_ldrv    = 0x1c000000u; // 0b00011100000000000000000000000000 \"LDR St/Dt/Qt, label\" | ADDR_PCREL19\n    static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000\n    static constexpr uint32_t op_ldrsw   = 0x98000000u; // \"LDRSW Xt, label\" | ADDR_PCREL19 | load register signed word\n    // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit\n    // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit\n    // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit\n    // INVALID    | 0b11011100000000000000000000000000 | may be 256-bit\n\n    uint32_t  mask     = mask_ldr;\n    uintptr_t faligned = (ins & mask_30) ? 7u : 3u;\n    if ((ins & mask_ldr) != op_ldr) {\n        mask = mask_ldrv;\n        if (faligned != 7u)\n            faligned = (ins & mask_31) ? 15u : 3u;\n        if ((ins & mask_ldrv) != op_ldrv) {\n            if ((ins & mask_ldrsw) != op_ldrsw) {\n                return false;\n            } //if\n            mask     = mask_ldrsw;\n            faligned = 7u;\n        } //if\n    } //if\n\n    intptr_t current_idx  = ctxp->get_and_set_current_index(*inpp, *outpp);\n    int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + ((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u);\n    int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted\n    bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr);\n    // special_fix_type may encounter issue when there are mixed data and code\n    if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= (~lmask >> (lsb + 1))) { // inaccurate, but it works\n        while ((reinterpret_cast<uint64_t>(*outpp + 2) & faligned) != 0u) {\n            *(*outpp)++ = A64_NOP;\n        }\n        ctxp->reset_current_ins(current_idx, *outpp);\n\n        // Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it.\n        // And what's worse, we may unexpectedly overwrite something if special_fix_type is true...\n        uint32_t ns = static_cast<uint32_t>((faligned + 1) / sizeof(uint32_t));\n        (*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8\n        (*outpp)[1] = 0x14000001u + ns; // B #0xc\n        memcpy(*outpp + 2, reinterpret_cast<void *>(absolute_addr), faligned + 1);\n        *outpp += 2 + ns;\n    } else {\n        faligned >>= 2; // new_pc_offset is shifted and 4-byte aligned\n        while ((new_pc_offset & faligned) != 0) {\n            *(*outpp)++   = A64_NOP;\n            new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2;\n        }\n        ctxp->reset_current_ins(current_idx, *outpp);\n\n        (*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << lsb) & ~mask) | (ins & lmask);\n        ++(*outpp);\n    } //if\n\n    ++(*inpp);\n    return ctxp->process_fix_map(current_idx), true;\n}\n\n//-------------------------------------------------------------------------\n\nstatic bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp)\n{\n    // Load a PC-relative address into a register\n    // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html\n    static constexpr uint32_t msb     = 8u;\n    static constexpr uint32_t lsb     = 5u;\n    static constexpr uint32_t mask    = 0x9f000000u; // 0b10011111000000000000000000000000\n    static constexpr uint32_t rmask   = 0x0000001fu; // 0b00000000000000000000000000011111\n    static constexpr uint32_t lmask   = 0xff00001fu; // 0b11111111000000000000000000011111\n    static constexpr uint32_t fmask   = 0x00ffffffu; // 0b00000000111111111111111111111111\n    static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111\n    static constexpr uint32_t op_adr  = 0x10000000u; // \"adr\"  Rd, ADDR_PCREL21\n    static constexpr uint32_t op_adrp = 0x90000000u; // \"adrp\" Rd, ADDR_ADRP\n\n    const uint32_t ins = *(*inpp);\n    intptr_t current_idx;\n    switch (ins & mask) {\n        case op_adr:\n        {\n            current_idx           = ctxp->get_and_set_current_index(*inpp, *outpp);\n            int64_t lsb_bytes     = static_cast<uint32_t>(ins << 1u) >> 30u;\n            int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + (((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes);\n            int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp));\n            bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr);\n            if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) {\n                if ((reinterpret_cast<uint64_t>(*outpp + 2) & 7u) != 0u) {\n                    (*outpp)[0] = A64_NOP;\n                    ctxp->reset_current_ins(current_idx, ++(*outpp));\n                } //if\n\n                (*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8\n                (*outpp)[1] = 0x14000003u; // B #0xc\n                memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr));\n                *outpp += 4;\n            } else {\n                if (special_fix_type) {\n                    intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull);\n                    if (ref_idx <= current_idx) {\n                        new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp));\n                    } else {\n                        ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask);\n                        new_pc_offset = 0;\n                    } //if\n                } //if\n\n                // the lsb_bytes will never be changed, so we can use lmask to keep it\n                (*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << (lsb - 2u)) & fmask) | (ins & lmask);\n                ++(*outpp);\n            } //if\n        }\n            break;\n        case op_adrp:\n        {\n            current_idx           = ctxp->get_and_set_current_index(*inpp, *outpp);\n            int32_t lsb_bytes     = static_cast<uint32_t>(ins << 1u) >> 30u;\n            int64_t absolute_addr = (reinterpret_cast<int64_t>(*inpp) & ~0xfffll) + ((((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes) << 12);\n            if (ctxp->is_in_fixing_range(absolute_addr)) {\n                intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/);\n                if (ref_idx > current_idx) {\n                    // the bottom 12 bits of absolute_addr are masked out,\n                    // so ref_idx must be less than or equal to current_idx!\n                } //if\n\n                // *absolute_addr may be changed due to relocation fixing\n                *(*outpp)++ = ins; // 0x90000000u;\n            } else {\n                if ((reinterpret_cast<uint64_t>(*outpp + 2) & 7u) != 0u) {\n                    (*outpp)[0] = A64_NOP;\n                    ctxp->reset_current_ins(current_idx, ++(*outpp));\n                } //if\n\n                (*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8\n                (*outpp)[1] = 0x14000003u; // B #0xc\n                memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow?\n                *outpp += 4;\n            } //if\n        }\n            break;\n        default:\n            return false;\n    }\n\n    ctxp->process_fix_map(current_idx);\n    ++(*inpp);\n    return true;\n}\n\n//-------------------------------------------------------------------------\n\nstatic void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp)\n{\n    context ctx;\n    ctx.basep = reinterpret_cast<int64_t>(inp);\n    ctx.endp  = reinterpret_cast<int64_t>(inp + count);\n    memset(ctx.dat, 0, sizeof(ctx.dat));\n    static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS,\n                  \"please use A64_MAX_INSTRUCTIONS!\");\n#ifndef NDEBUG\n    if (count > A64_MAX_INSTRUCTIONS) {\n        A64_LOGE(\"too many fixing instructions!\");\n    } //if\n#endif // NDEBUG\n\n    uint32_t *const outp_base = outp;\n\n    while (--count >= 0) {\n        if (__fix_branch_imm(&inp, &outp, &ctx)) continue;\n        if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue;\n        if (__fix_loadlit(&inp, &outp, &ctx)) continue;\n        if (__fix_pcreladdr(&inp, &outp, &ctx)) continue;\n\n        // without PC-relative offset\n        ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp));\n        *(outp++) = *(inp++);\n    }\n\n    static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111\n    auto callback  = reinterpret_cast<int64_t>(inp);\n    auto pc_offset = static_cast<int64_t>(callback - reinterpret_cast<int64_t>(outp)) >> 2;\n    if (llabs(pc_offset) >= (mask >> 1)) {\n        if ((reinterpret_cast<uint64_t>(outp + 2) & 7u) != 0u) {\n            outp[0] = A64_NOP;\n            ++outp;\n        } //if\n        outp[0] = 0x58000051u; // LDR X17, #0x8\n        outp[1] = 0xd61f0220u; // BR X17\n        *reinterpret_cast<int64_t *>(outp + 2) = callback;\n        outp += 4;\n    } else {\n        outp[0] = 0x14000000u | (pc_offset & mask); // \"B\" ADDR_PCREL26\n        ++outp;\n    } //if\n\n    const uintptr_t total = (outp - outp_base) * sizeof(uint32_t);\n    __flush_cache(outp_base, total); // necessary\n}\n\n//-------------------------------------------------------------------------\n\nextern \"C\" {\n#define __attribute                __attribute__\n#define aligned(x)                 __aligned__(x)\n#define __intval(p)                reinterpret_cast<intptr_t>(p)\n#define __uintval(p)               reinterpret_cast<uintptr_t>(p)\n#define __ptr(p)                   reinterpret_cast<void *>(p)\n#define __page_size                4096\n#define __page_align(n)            __align_up(static_cast<uintptr_t>(n), __page_size)\n#define __ptr_align(x)             __ptr(__align_down(reinterpret_cast<uintptr_t>(x), __page_size))\n#define __align_up(x, n)           (((x) + ((n) - 1)) & ~((n) - 1))\n#define __align_down(x, n)         ((x) & -(n))\n#define __countof(x)               static_cast<intptr_t>(sizeof(x) / sizeof((x)[0])) // must be signed\n#define __atomic_increase(p)       __sync_add_and_fetch(p, 1)\n#define __sync_cmpswap(p, v, n)    __sync_bool_compare_and_swap(p, v, n)\n#define __predict_true(exp)        __builtin_expect((exp) != 0, 1)\n#define __make_rwx(p, n)           ::mprotect(__ptr_align(p), \\\n                                              __page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \\\n                                              PROT_READ | PROT_WRITE | PROT_EXEC)\n\n//-------------------------------------------------------------------------\n\nstatic __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][A64_MAX_INSTRUCTIONS * 10];\n\n//-------------------------------------------------------------------------\n\nclass A64HookInit\n{\npublic:\n    A64HookInit()\n    {\n        __make_rwx(__insns_pool, sizeof(__insns_pool));\n    }\n};\nstatic A64HookInit __init;\n\n//-------------------------------------------------------------------------\n\nstatic uint32_t *FastAllocateTrampoline()\n{\n    static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, \"8-byte align\");\n    static volatile int32_t __index = -1;\n\n    int32_t i = __atomic_increase(&__index);\n    if (__predict_true(i >= 0 && i < __countof(__insns_pool))) {\n        return __insns_pool[i];\n    } //if\n\n    return NULL;\n}\n\n//-------------------------------------------------------------------------\n\nA64_JNIEXPORT void *A64HookFunctionV(void *const symbol, void *const replace,\n                                     void *const rwx, const uintptr_t rwx_size)\n{\n    static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111\n\n    uint32_t *trampoline = static_cast<uint32_t *>(rwx), *original = static_cast<uint32_t *>(symbol);\n\n    static_assert(A64_MAX_INSTRUCTIONS >= 5, \"please fix A64_MAX_INSTRUCTIONS!\");\n    auto pc_offset = static_cast<int64_t>(__intval(replace) - __intval(symbol)) >> 2;\n    if (llabs(pc_offset) >= (mask >>1)) {\n        int32_t count = (reinterpret_cast<uint64_t>(original + 2) & 7u) != 0u ? 5 : 4;\n        if (trampoline) {\n            if (rwx_size < count * 10u) {\n                return NULL;\n            } //if\n            __fix_instructions(original, count, trampoline);\n        } //if\n\n        if (__make_rwx(original, 5 * sizeof(uint32_t)) == 0) {\n            if (count == 5) {\n                original[0] = A64_NOP;\n                ++original;\n            } //if\n            original[0] = 0x58000051u; // LDR X17, #0x8\n            original[1] = 0xd61f0220u; // BR X17\n            *reinterpret_cast<int64_t *>(original + 2) = __intval(replace);\n            __flush_cache(symbol, 5 * sizeof(uint32_t));\n\n        } else {\n            trampoline = NULL;\n        } //if\n    } else {\n        if (trampoline) {\n            if (rwx_size < 1u * 10u) {\n                return NULL;\n            } //if\n            __fix_instructions(original, 1, trampoline);\n        } //if\n\n        if (__make_rwx(original, 1 * sizeof(uint32_t)) == 0) {\n            __sync_cmpswap(original, *original, 0x14000000u | (pc_offset & mask)); // \"B\" ADDR_PCREL26\n            __flush_cache(symbol, 1 * sizeof(uint32_t));\n\n        } else {\n            trampoline = NULL;\n        } //if\n    } //if\n\n    return trampoline;\n}\n\n//-------------------------------------------------------------------------\n\nA64_JNIEXPORT void A64HookFunction(void *const symbol, void *const replace, void **result)\n{\n    void *trampoline = NULL;\n    if (result != NULL) {\n        trampoline = FastAllocateTrampoline();\n        *result = trampoline;\n        if (trampoline == NULL) return;\n    } //if\n\n    trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u);\n    if (trampoline == NULL && result != NULL) {\n        *result = NULL;\n    } //if\n}\n}\n\n#endif // defined(__aarch64__)"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/A64Inlinehook/And64InlineHook.hpp",
    "content": "/*\n *  @date   : 2018/04/18\n *  @author : Rprop (r_prop@outlook.com)\n *  https://github.com/Rprop/And64InlineHook\n */\n/*\n MIT License\n\n Copyright (c) 2018 Rprop (r_prop@outlook.com)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n#pragma once\n\n#include <stdint.h>\n\n#define A64_MAX_BACKUPS 256\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid A64HookFunction(void *const symbol, void *const replace, void **result);\nvoid *A64HookFunctionV(void *const symbol, void *const replace,\n                       void *const rwx, const uintptr_t rwx_size);\n\n#ifdef __cplusplus\n}\n#endif"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Android.mk",
    "content": "LOCAL_PATH := $(call my-dir)\nMAIN_LOCAL_PATH := $(call my-dir)\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := va++\n\nLOCAL_CFLAGS := -Wno-error=format-security -fpermissive -DLOG_TAG=\\\"VA++\\\"\nLOCAL_CFLAGS += -fno-rtti -fno-exceptions\n\nLOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)\nLOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)/Foundation\nLOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)/Jni\n\nLOCAL_SRC_FILES := Jni/VAJni.cpp \\\n\t\t\t\t   Foundation/IOUniformer.cpp \\\n\t\t\t\t   Foundation/VMPatch.cpp \\\n\t\t\t\t   Foundation/SymbolFinder.cpp \\\n\t\t\t\t   Foundation/Path.cpp \\\n\t\t\t\t   Foundation/SandboxFs.cpp \\\n\t\t\t\t   Foundation/fake_dlfcn.cpp \\\n\t\t\t\t   Substrate/hde64.c \\\n                   Substrate/SubstrateDebug.cpp \\\n                   Substrate/SubstrateHook.cpp \\\n                   Substrate/SubstratePosixMemory.cpp \\\n                   A64Inlinehook/And64InlineHook.cpp\n\nLOCAL_LDLIBS := -llog -latomic\nLOCAL_STATIC_LIBRARIES := fb\n\ninclude $(BUILD_SHARED_LIBRARY)\ninclude $(MAIN_LOCAL_PATH)/fb/Android.mk"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Application.mk",
    "content": "APP_ABI := x86_64 arm64-v8a\nAPP_PLATFORM := android-14\nAPP_STL := c++_static\nAPP_OPTIM := release\nVA_ROOT          := $(call my-dir)\nNDK_MODULE_PATH  := $(NDK_MODULE_PATH):$(VA_ROOT)"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/IOUniformer.cpp",
    "content": "//\n// VirtualApp Native Project\n//\n#include <unistd.h>\n#include <stdlib.h>\n#include <fb/include/fb/ALog.h>\n\n#ifdef __aarch64__\n#include \"A64Inlinehook/And64InlineHook.hpp\"\n#else\n#include <Substrate/SubstrateHook.h>\n#endif\n\n//extern \"C\" {\n//#include <HookZz/include/hookzz.h>\n//}\n\n\n#include \"IOUniformer.h\"\n#include \"SandboxFs.h\"\n#include \"Path.h\"\n#include \"SymbolFinder.h\"\n\nbool iu_loaded = false;\n\nvoid IOUniformer::init_env_before_all() {\n    if (iu_loaded)\n        return;\n    char *api_level_chars = getenv(\"V_API_LEVEL\");\n    char *preview_api_level_chars = getenv(\"V_PREVIEW_API_LEVEL\");\n    if (api_level_chars) {\n        ALOGE(\"Enter init before all.\");\n        int api_level = atoi(api_level_chars);\n        int preview_api_level;\n        preview_api_level = atoi(preview_api_level_chars);\n        char keep_env_name[25];\n        char forbid_env_name[25];\n        char replace_src_env_name[25];\n        char replace_dst_env_name[25];\n        int i = 0;\n        while (true) {\n            sprintf(keep_env_name, \"V_KEEP_ITEM_%d\", i);\n            char *item = getenv(keep_env_name);\n            if (!item) {\n                break;\n            }\n            add_keep_item(item);\n            i++;\n        }\n        i = 0;\n        while (true) {\n            sprintf(forbid_env_name, \"V_FORBID_ITEM_%d\", i);\n            char *item = getenv(forbid_env_name);\n            if (!item) {\n                break;\n            }\n            add_forbidden_item(item);\n            i++;\n        }\n        i = 0;\n        while (true) {\n            sprintf(replace_src_env_name, \"V_REPLACE_ITEM_SRC_%d\", i);\n            char *item_src = getenv(replace_src_env_name);\n            if (!item_src) {\n                break;\n            }\n            sprintf(replace_dst_env_name, \"V_REPLACE_ITEM_DST_%d\", i);\n            char *item_dst = getenv(replace_dst_env_name);\n            add_replace_item(item_src, item_dst);\n            i++;\n        }\n        startUniformer(getenv(\"V_SO_PATH\"),api_level, preview_api_level);\n        iu_loaded = true;\n    }\n}\n\nstatic inline void\nhook_function(void *addr, void *new_func, void **old_func) {\n#ifdef __aarch64__\n    A64HookFunction(addr, new_func, old_func);\n#else\n    MSHookFunction(addr, new_func, old_func);\n#endif\n\n}\n\nstatic inline void\nhook_function(void *handle, const char *symbol, void *new_func, void **old_func) {\n    void *addr = dlsym(handle, symbol);\n    if (addr == NULL) {\n        return;\n    }\n    hook_function(addr, new_func, old_func);\n}\n\n\nvoid onSoLoaded(const char *name, void *handle);\n\nvoid IOUniformer::redirect(const char *orig_path, const char *new_path) {\n    add_replace_item(orig_path, new_path);\n}\n\nconst char *IOUniformer::query(const char *orig_path) {\n    return reverse_relocate_path(orig_path);\n}\n\nvoid IOUniformer::whitelist(const char *_path) {\n    add_keep_item(_path);\n}\n\nvoid IOUniformer::forbid(const char *_path) {\n    add_forbidden_item(_path);\n}\n\n\nconst char *IOUniformer::reverse(const char *_path) {\n    return reverse_relocate_path(_path);\n}\n\n\n__BEGIN_DECLS\n\n#define FREE(ptr, org_ptr) { if ((void*) ptr != NULL && (void*) ptr != (void*) org_ptr) { free((void*) ptr); } }\n\n\n\n// int fstatat64(int dirfd, const char *pathname, struct stat *buf, int flags);\nHOOK_DEF(int, fstatat64, int dirfd, const char *pathname, struct stat *buf, int flags) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_newfstatat, dirfd, redirect_path, buf, flags);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);\nHOOK_DEF(int, mknodat, int dirfd, const char *pathname, mode_t mode, dev_t dev) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_mknodat, dirfd, redirect_path, mode, dev);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);\nHOOK_DEF(int, utimensat, int dirfd, const char *pathname, const struct timespec times[2],\n         int flags) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_utimensat, dirfd, redirect_path, times, flags);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags);\nHOOK_DEF(int, fchownat, int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_fchownat, dirfd, redirect_path, owner, group, flags);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n// int chroot(const char *pathname);\nHOOK_DEF(int, chroot, const char *pathname) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_chroot, redirect_path);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);\nHOOK_DEF(int, renameat, int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {\n    int res_old;\n    int res_new;\n    const char *redirect_path_old = relocate_path(oldpath, &res_old);\n    const char *redirect_path_new = relocate_path(newpath, &res_new);\n    int ret = syscall(__NR_renameat, olddirfd, redirect_path_old, newdirfd, redirect_path_new);\n    FREE(redirect_path_old, oldpath);\n    FREE(redirect_path_new, newpath);\n    return ret;\n}\n\n\n// int unlinkat(int dirfd, const char *pathname, int flags);\nHOOK_DEF(int, unlinkat, int dirfd, const char *pathname, int flags) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_unlinkat, dirfd, redirect_path, flags);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int symlinkat(const char *oldpath, int newdirfd, const char *newpath);\nHOOK_DEF(int, symlinkat, const char *oldpath, int newdirfd, const char *newpath) {\n    int res_old;\n    int res_new;\n    const char *redirect_path_old = relocate_path(oldpath, &res_old);\n    const char *redirect_path_new = relocate_path(newpath, &res_new);\n    int ret = syscall(__NR_symlinkat, redirect_path_old, newdirfd, redirect_path_new);\n    FREE(redirect_path_old, oldpath);\n    FREE(redirect_path_new, newpath);\n    return ret;\n}\n\n// int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags);\nHOOK_DEF(int, linkat, int olddirfd, const char *oldpath, int newdirfd, const char *newpath,\n         int flags) {\n    int res_old;\n    int res_new;\n    const char *redirect_path_old = relocate_path(oldpath, &res_old);\n    const char *redirect_path_new = relocate_path(newpath, &res_new);\n    int ret = syscall(__NR_linkat, olddirfd, redirect_path_old, newdirfd, redirect_path_new, flags);\n    FREE(redirect_path_old, oldpath);\n    FREE(redirect_path_new, newpath);\n    return ret;\n}\n\n\n// int mkdirat(int dirfd, const char *pathname, mode_t mode);\nHOOK_DEF(int, mkdirat, int dirfd, const char *pathname, mode_t mode) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_mkdirat, dirfd, redirect_path, mode);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);\nHOOK_DEF(int, readlinkat, int dirfd, const char *pathname, char *buf, size_t bufsiz) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_readlinkat, dirfd, redirect_path, buf, bufsiz);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n// int truncate(const char *path, off_t length);\nHOOK_DEF(int, truncate, const char *pathname, off_t length) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    int ret = syscall(__NR_truncate, redirect_path, length);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n#define RETURN_IF_FORBID if(res == FORBID) return -1;\n\n\n// int chdir(const char *path);\nHOOK_DEF(int, chdir, const char *pathname) {\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    RETURN_IF_FORBID\n    int ret = syscall(__NR_chdir, redirect_path);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\n// int __statfs (__const char *__file, struct statfs *__buf);\nHOOK_DEF(int, __statfs, __const char *__file, struct statfs *__buf) {\n    int res;\n    const char *redirect_path = relocate_path(__file, &res);\n    int ret = syscall(__NR_statfs, redirect_path, __buf);\n    FREE(redirect_path, __file);\n    return ret;\n}\n\n// int statfs64 (__const char *__file, struct statfs *__buf);\nHOOK_DEF(int, statfs64, __const char *__file, struct statfs *__buf) {\n    int res;\n    const char *redirect_path = relocate_path(__file, &res);\n    int ret = syscall(__NR_statfs, redirect_path, __buf);\n    FREE(redirect_path, __file);\n    return ret;\n}\n\nint inline getArrayItemCount(char *const array[]) {\n    int i;\n    for (i = 0; array[i]; ++i);\n    return i;\n}\n\n\nchar **build_new_env(char *const envp[]) {\n    char *provided_ld_preload = NULL;\n    int provided_ld_preload_index = -1;\n    int orig_envp_count = getArrayItemCount(envp);\n\n    for (int i = 0; i < orig_envp_count; i++) {\n        if (strstr(envp[i], \"LD_PRELOAD\")) {\n            provided_ld_preload = envp[i];\n            provided_ld_preload_index = i;\n        }\n    }\n    char ld_preload[200];\n    char *so_path = getenv(\"V_SO_PATH\");\n    if (provided_ld_preload) {\n        sprintf(ld_preload, \"LD_PRELOAD=%s:%s\", so_path, provided_ld_preload + 11);\n    } else {\n        sprintf(ld_preload, \"LD_PRELOAD=%s\", so_path);\n    }\n    int new_envp_count = orig_envp_count\n                         + get_keep_item_count()\n                         + get_forbidden_item_count()\n                         + get_replace_item_count() * 2 + 1;\n    if (provided_ld_preload) {\n        new_envp_count--;\n    }\n    char **new_envp = (char **) malloc(new_envp_count * sizeof(char *));\n    int cur = 0;\n    new_envp[cur++] = ld_preload;\n    for (int i = 0; i < orig_envp_count; ++i) {\n        if (i != provided_ld_preload_index) {\n            new_envp[cur++] = envp[i];\n        }\n    }\n    for (int i = 0; environ[i]; ++i) {\n        if (environ[i][0] == 'V' && environ[i][1] == '_') {\n            new_envp[cur++] = environ[i];\n        }\n    }\n    new_envp[cur] = NULL;\n    return new_envp;\n}\n\nchar **build_new_argv(char *const envp[]) {\n    char *provided_ld_preload = NULL;\n    int provided_ld_preload_index = -1;\n    int orig_envp_count = getArrayItemCount(envp);\n\n    for (int i = 0; i < orig_envp_count; i++) {\n        if (strstr(envp[i], \"compiler-filter\")) {\n            provided_ld_preload = envp[i];\n            provided_ld_preload_index = i;\n        }\n    }\n    char ld_preload[40];\n    if (provided_ld_preload) {\n        sprintf(ld_preload, \"--compiler-filter=%s\", \"everything\");\n    }\n\n    char *api_level_char = getenv(\"V_API_LEVEL\");\n    int api_level = atoi(api_level_char);\n\n    int new_envp_count = orig_envp_count + 4;\n    char **new_envp = (char **) malloc(new_envp_count * sizeof(char *));\n    int cur = 0;\n    for (int i = 0; i < orig_envp_count; ++i) {\n        if (i != provided_ld_preload_index) {\n            new_envp[cur++] = envp[i];\n        } else {\n            new_envp[i] = ld_preload;\n            cur++;\n        }\n    }\n\n    if (api_level >= 22) {\n        new_envp[cur++] = (char *) \"--compile-pic\";\n    }\n    if (api_level >= 23) {\n        new_envp[cur++] = (char *) (api_level > 25 ? \"--inline-max-code-units=0\" : \"--inline-depth-limit=0\");\n    }\n    if (api_level >= 28) {\n        new_envp[cur++] = (char *) \"--debuggable\";\n    }\n    new_envp[cur] = NULL;\n\n//    int n = getArrayItemCount(new_envp);\n//    for (int i = 0; i < n; i++) {\n//        ALOGE(\"dex2oat : %s\", new_envp[i]);\n//    }\n\n    return new_envp;\n}\n\n// int (*origin_execve)(const char *pathname, char *const argv[], char *const envp[]);\nHOOK_DEF(int, execve, const char *pathname, char *argv[], char *const envp[]) {\n    /**\n     * CANNOT LINK EXECUTABLE \"/system/bin/cat\": \"/data/app/io.virtualapp-1/lib/arm/libva-native.so\" is 32-bit instead of 64-bit.\n     *\n     * We will support 64Bit to adopt it.\n     */\n    // ALOGE(\"execve : %s\", pathname); // any output can break exec. See bug: https://issuetracker.google.com/issues/109448553\n    int res;\n    const char *redirect_path = relocate_path(pathname, &res);\n    char *ld = getenv(\"LD_PRELOAD\");\n    if (ld) {\n        if (strstr(ld, \"libNimsWrap.so\") || strstr(ld, \"stamina.so\")) {\n            int ret = syscall(__NR_execve, redirect_path, argv, envp);\n            FREE(redirect_path, pathname);\n            return ret;\n        }\n    }\n    if (strstr(pathname, \"dex2oat\")) {\n        char **new_envp = build_new_env(envp);\n        char **new_argv = build_new_argv(argv);\n        int ret = syscall(__NR_execve, redirect_path, new_argv, new_envp);\n        FREE(redirect_path, pathname);\n        free(new_envp);\n        free(new_argv);\n        return ret;\n    }\n    int ret = syscall(__NR_execve, redirect_path, argv, envp);\n    FREE(redirect_path, pathname);\n    return ret;\n}\n\n\nHOOK_DEF(void*, dlopen, const char *filename, int flag) {\n    int res;\n    const char *redirect_path = relocate_path(filename, &res);\n    void *ret = orig_dlopen(redirect_path, flag);\n    onSoLoaded(filename, ret);\n    ALOGD(\"dlopen : %s, return : %p.\", redirect_path, ret);\n    FREE(redirect_path, filename);\n    return ret;\n}\n\nHOOK_DEF(void*, do_dlopen_V19, const char *filename, int flag, const void *extinfo) {\n    int res;\n    const char *redirect_path = relocate_path(filename, &res);\n    void *ret = orig_do_dlopen_V19(redirect_path, flag, extinfo);\n    onSoLoaded(filename, ret);\n    ALOGD(\"do_dlopen : %s, return : %p.\", redirect_path, ret);\n    FREE(redirect_path, filename);\n    return ret;\n}\n\nHOOK_DEF(void*, do_dlopen_V24, const char *name, int flags, const void *extinfo,\n         void *caller_addr) {\n    int res;\n    const char *redirect_path = relocate_path(name, &res);\n    void *ret = orig_do_dlopen_V24(redirect_path, flags, extinfo, caller_addr);\n    onSoLoaded(name, ret);\n    ALOGD(\"do_dlopen : %s, return : %p.\", redirect_path, ret);\n    FREE(redirect_path, name);\n    return ret;\n}\n\n\n\n//void *dlsym(void *handle,const char *symbol)\nHOOK_DEF(void*, dlsym, void *handle, char *symbol) {\n    ALOGD(\"dlsym : %p %s.\", handle, symbol);\n    return orig_dlsym(handle, symbol);\n}\n\n// int kill(pid_t pid, int sig);\nHOOK_DEF(int, kill, pid_t pid, int sig) {\n    ALOGD(\">>>>> kill >>> pid: %d, sig: %d.\", pid, sig);\n    int ret = syscall(__NR_kill, pid, sig);\n    return ret;\n}\n\nHOOK_DEF(pid_t, vfork) {\n    return fork();\n}\n\n__END_DECLS\n// end IO DEF\n\n\nvoid onSoLoaded(const char *name, void *handle) {\n}\n\nint findSymbol(const char *name, const char *libn,\n               unsigned long *addr) {\n    return find_name(getpid(), name, libn, addr);\n}\n\nvoid hook_dlopen(int api_level) {\n    void *symbol = NULL;\n    if (api_level > 25) {\n        if (findSymbol(\"__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv\", \"linker\",\n                       (unsigned long *) &symbol) == 0) {\n            hook_function(symbol, (void *) new_do_dlopen_V24,\n                           (void **) &orig_do_dlopen_V24);\n        }\n    } else if (api_level > 23) {\n        if (findSymbol(\"__dl__Z9do_dlopenPKciPK17android_dlextinfoPv\", \"linker\",\n                       (unsigned long *) &symbol) == 0) {\n            hook_function(symbol, (void *) new_do_dlopen_V24,\n                          (void **) &orig_do_dlopen_V24);\n        }\n    } else if (api_level >= 19) {\n        if (findSymbol(\"__dl__Z9do_dlopenPKciPK17android_dlextinfo\", \"linker\",\n                       (unsigned long *) &symbol) == 0) {\n            hook_function(symbol, (void *) new_do_dlopen_V19,\n                          (void **) &orig_do_dlopen_V19);\n        }\n    } else {\n        if (findSymbol(\"__dl_dlopen\", \"linker\",\n                       (unsigned long *) &symbol) == 0) {\n            hook_function(symbol, (void *) new_dlopen, (void **) &orig_dlopen);\n        }\n    }\n}\n\n\nvoid IOUniformer::startUniformer(const char *so_path, int api_level, int preview_api_level) {\n    char api_level_chars[5];\n    setenv(\"V_SO_PATH\", so_path, 1);\n    sprintf(api_level_chars, \"%i\", api_level);\n    setenv(\"V_API_LEVEL\", api_level_chars, 1);\n    sprintf(api_level_chars, \"%i\", preview_api_level);\n    setenv(\"V_PREVIEW_API_LEVEL\", api_level_chars, 1);\n\n    void *handle = dlopen(\"libc.so\", RTLD_NOW);\n    if (handle) {\n        HOOK_SYMBOL(handle, fchownat);\n        HOOK_SYMBOL(handle, renameat);\n        HOOK_SYMBOL(handle, fstatat64);\n        HOOK_SYMBOL(handle, __statfs);\n        HOOK_SYMBOL(handle, mkdirat);\n        HOOK_SYMBOL(handle, mknodat);\n        HOOK_SYMBOL(handle, truncate);\n        HOOK_SYMBOL(handle, linkat);\n        HOOK_SYMBOL(handle, readlinkat);\n        HOOK_SYMBOL(handle, unlinkat);\n        HOOK_SYMBOL(handle, symlinkat);\n        HOOK_SYMBOL(handle, utimensat);\n        HOOK_SYMBOL(handle, chdir);\n        HOOK_SYMBOL(handle, execve);\n        HOOK_SYMBOL(handle, statfs64);\n        dlclose(handle);\n    }\n    // hook_dlopen(api_level);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/IOUniformer.h",
    "content": "//\n// VirtualApp Native Project\n//\n\n#ifndef NDK_HOOK_H\n#define NDK_HOOK_H\n\n\n#include <string>\n#include <map>\n#include <list>\n#include <jni.h>\n#include <dlfcn.h>\n#include <stddef.h>\n#include <fcntl.h>\n#include<dirent.h>\n#include <sys/syscall.h>\n\n#include \"Jni/Helper.h\"\n\n\n#define HOOK_SYMBOL(handle, func) hook_function(handle, #func, (void*) new_##func, (void**) &orig_##func)\n#define HOOK_DEF(ret, func, ...) \\\n  ret (*orig_##func)(__VA_ARGS__); \\\n  ret new_##func(__VA_ARGS__)\n\n\nnamespace IOUniformer {\n\n    void init_env_before_all();\n\n    void startUniformer(const char *so_path, int api_level, int preview_api_level);\n\n    void redirect(const char *orig_path, const char *new_path);\n\n    void whitelist(const char *path);\n\n    const char *query(const char *orig_path);\n\n    const char *reverse(const char *redirected_path);\n\n    void forbid(const char *path);\n}\n\n#endif //NDK_HOOK_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/Path.cpp",
    "content": "#include \"Path.h\"\n#define MAX_PATH_SIZE 4096\n\n/* returns last slash position in @s or -1 if there is no one */\nint get_last_slash_pos(char *s) {\n    int last_slash = -1;\n    char *slash = strrchr(s, '/');\n    if (slash)\n        last_slash = slash - s;\n    return last_slash;\n}\n\nchar *canonicalize_filename(const char *str) {\n    int prev_last_slash = -1;\n    int last_slash = -1;\n    int i = 0;\n    int j = 0;\n    char c;\n    char cprev = '\\0';\n    char result[MAX_PATH_SIZE] = {0};\n\n    if (!str)\n        return NULL;\n\n    for (; i < MAX_PATH_SIZE && str[i]; ++i) {\n        c = str[i];\n\n        switch (c) {\n            case '/':\n                if (cprev == '/'/** || j == 0*/) {\n                    // eat repeating and leading slashes\n                    ;\n                } else {\n                    result[j++] = c;\n                    prev_last_slash = last_slash;\n                    last_slash = j - 1;\n                }\n                break;\n            case '.':\n                if (cprev == '.') {\n                    int start_position = 0;\n                    if (prev_last_slash > 0) {\n                        start_position = prev_last_slash;\n                        // handle following duplicate slash on next iteration, if any\n                        cprev = '/';\n                    }\n                    while (j > start_position)\n                        result[j--] = '\\0';\n                    result[j] = '\\0';\n\n                    // we lost last slash positions, calculate them\n                    prev_last_slash = -1;\n                    last_slash = get_last_slash_pos(result);\n                    if (last_slash != -1) {\n                        // trying to find previous last slash position\n                        result[last_slash] = ' ';\n                        prev_last_slash = get_last_slash_pos(result);\n                        result[last_slash] = '/';\n                    }\n                } else {\n                    // assume it is a valid to have dot in names\n                    result[j++] = c;\n                }\n                break;\n            default:\n                result[j++] = c;\n                break;\n        }\n        cprev = c;\n    }\n    return strndup(result, MAX_PATH_SIZE - 1);\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/Path.h",
    "content": "//\n// VirtualApp Native Project\n//\n\n#ifndef FOUNDATION_PATH\n#define FOUNDATION_PATH\n\n#include <string.h>\n\nint get_last_slash_pos(char *s);\n\nchar* canonicalize_filename(const char *str);\n\n\n#endif //FOUNDATION_PATH\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/SandboxFs.cpp",
    "content": "#include <stdlib.h>\n#include \"SandboxFs.h\"\n#include \"Path.h\"\n\nPathItem *keep_items;\nPathItem *forbidden_items;\nReplaceItem *replace_items;\nint keep_item_count;\nint forbidden_item_count;\nint replace_item_count;\n\nint add_keep_item(const char *path) {\n    char keep_env_name[25];\n    sprintf(keep_env_name, \"V_KEEP_ITEM_%d\", keep_item_count);\n    setenv(keep_env_name, path, 1);\n    keep_items = (PathItem *) realloc(keep_items,\n                                      keep_item_count * sizeof(PathItem) + sizeof(PathItem));\n    PathItem &item = keep_items[keep_item_count];\n    item.path = strdup(path);\n    item.size = strlen(path);\n    return ++keep_item_count;\n}\n\nint add_forbidden_item(const char *path) {\n    char forbidden_env_name[25];\n    sprintf(forbidden_env_name, \"V_FORBID_ITEM_%d\", forbidden_item_count);\n    setenv(forbidden_env_name, path, 1);\n    forbidden_items = (PathItem *) realloc(forbidden_items,\n                                           forbidden_item_count * sizeof(PathItem) +\n                                           sizeof(PathItem));\n    PathItem &item = forbidden_items[forbidden_item_count];\n    item.path = strdup(path);\n    item.size = strlen(path);\n    item.is_folder = (path[strlen(path) - 1] == '/');\n    return ++forbidden_item_count;\n}\n\nint add_replace_item(const char *orig_path, const char *new_path) {\n    char src_env_name[25];\n    char dst_env_name[25];\n    sprintf(src_env_name, \"V_REPLACE_ITEM_SRC_%d\", replace_item_count);\n    sprintf(dst_env_name, \"V_REPLACE_ITEM_DST_%d\", replace_item_count);\n    setenv(src_env_name, orig_path, 1);\n    setenv(dst_env_name, new_path, 1);\n\n    replace_items = (ReplaceItem *) realloc(replace_items,\n                                            replace_item_count * sizeof(ReplaceItem) +\n                                            sizeof(ReplaceItem));\n    ReplaceItem &item = replace_items[replace_item_count];\n    item.orig_path = strdup(orig_path);\n    item.orig_size = strlen(orig_path);\n    item.new_path = strdup(new_path);\n    item.new_size = strlen(new_path);\n    item.is_folder = (orig_path[strlen(orig_path) - 1] == '/');\n    return ++replace_item_count;\n}\n\n\nPathItem *get_keep_items() {\n    return keep_items;\n}\n\nPathItem *get_forbidden_item() {\n    return forbidden_items;\n}\n\nReplaceItem *get_replace_items() {\n    return replace_items;\n}\n\nint get_keep_item_count() {\n    return keep_item_count;\n}\n\nint get_forbidden_item_count() {\n    return forbidden_item_count;\n}\n\nint get_replace_item_count() {\n    return replace_item_count;\n}\n\ninline bool match_path(bool is_folder, size_t size, char *item_path, char *path) {\n    if (is_folder) {\n        if (strlen(path) < size) {\n            // ignore the last '/'\n            return strncmp(item_path, path, size - 1) == 0;\n        }\n    }\n    return strncmp(item_path, path, size) == 0;\n}\n\n\nconst char *relocate_path(const char *_path, int *result) {\n    if (_path == NULL) {\n        *result = NOT_MATCH;\n        return NULL;\n    }\n    char *path = canonicalize_filename(_path);\n    for (int i = 0; i < keep_item_count; ++i) {\n        PathItem &item = keep_items[i];\n        if (match_path(item.is_folder, item.size, item.path, path)) {\n            *result = KEEP;\n            free(path);\n            return _path;\n        }\n    }\n    for (int i = 0; i < forbidden_item_count; ++i) {\n        PathItem &item = forbidden_items[i];\n        if (match_path(item.is_folder, item.size, item.path, path)) {\n            *result = FORBID;\n            // Permission denied\n            errno = 13;\n            free(path);\n            return NULL;\n        }\n    }\n    for (int i = 0; i < replace_item_count; ++i) {\n        ReplaceItem &item = replace_items[i];\n        if (match_path(item.is_folder, item.orig_size, item.orig_path, path)) {\n            std::string redirect_path(item.new_path);\n            redirect_path += path + item.orig_size;\n            *result = MATCH;\n            free(path);\n            return strdup(redirect_path.c_str());\n        }\n    }\n    *result = NOT_MATCH;\n    return _path;\n}\n\n\nint relocate_path_inplace(char *_path, size_t size, int *result) {\n    const char *redirect_path = relocate_path(_path, result);\n    if (redirect_path && redirect_path != _path) {\n        if (strlen(redirect_path) <= size) {\n            strcpy(_path, redirect_path);\n        } else {\n            return -1;\n        }\n        free((void *) redirect_path);\n    }\n    return 0;\n}\n\n\nconst char *reverse_relocate_path(const char *_path) {\n    if (_path == NULL) {\n        return NULL;\n    }\n    char *path = canonicalize_filename(_path);\n    for (int i = 0; i < keep_item_count; ++i) {\n        PathItem &item = keep_items[i];\n        if (strcmp(item.path, path) == 0) {\n            free(path);\n            return _path;\n        }\n    }\n    for (int i = 0; i < replace_item_count; ++i) {\n        ReplaceItem &item = replace_items[i];\n        if (match_path(item.is_folder, item.new_size, item.new_path, path)) {\n            std::string reverse_path(item.orig_path);\n            reverse_path += path + item.new_size;\n            free(path);\n            return strdup(reverse_path.c_str());\n        }\n    }\n    return _path;\n}\n\n\nint reverse_relocate_path_inplace(char *_path, size_t size) {\n    const char *redirect_path = reverse_relocate_path(_path);\n    if (redirect_path && redirect_path != _path) {\n        if (strlen(redirect_path) <= size) {\n            strcpy(_path, redirect_path);\n        } else {\n            return -1;\n        }\n        free((void *) redirect_path);\n    }\n    return 0;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/SandboxFs.h",
    "content": "#ifndef SANDBOX_FS_H\n#define SANDBOX_FS_H\n\n#include <string>\n#include <errno.h>\n\ntypedef struct PathItem {\n    char *path;\n    bool is_folder;\n    size_t size;\n} PathItem;\n\ntypedef struct ReplaceItem {\n    char *orig_path;\n    size_t orig_size;\n    char *new_path;\n    size_t new_size;\n    bool is_folder;\n} ReplaceItem;\n\nenum RelocateResult {\n    MATCH,\n    NOT_MATCH,\n    FORBID,\n    KEEP\n};\n\n\nconst char *relocate_path(const char *_path, int *result);\n\nint relocate_path_inplace(char *_path, size_t size, int *result);\n\nconst char *reverse_relocate_path(const char *_path);\n\nint reverse_relocate_path_inplace(char *_path, size_t size);\n\nint add_keep_item(const char *path);\n\nint add_forbidden_item(const char *path);\n\nint add_replace_item(const char *orig_path, const char *new_path);\n\nPathItem *get_keep_items();\n\nPathItem *get_forbidden_item();\n\nReplaceItem *get_replace_items();\n\nint get_keep_item_count();\n\nint get_forbidden_item_count();\n\nint get_replace_item_count();\n\n\n#endif //SANDBOX_FS_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/SymbolFinder.cpp",
    "content": "#include <stdio.h>\n#include <elf.h>\n#include <Jni/Helper.h>\n#include <malloc.h>\n#include <stdlib.h>\n#include <fcntl.h>\n#include <sys/mman.h>\n#include <fb/include/fb/ALog.h>\n#include \"SymbolFinder.h\"\n\n/* memory map for libraries */\n#define MAX_NAME_LEN 256\n#define MEMORY_ONLY  \"[memory]\"\nstruct mm {\n    char name[MAX_NAME_LEN];\n    unsigned long start, end;\n};\n\ntypedef struct symtab *symtab_t;\nstruct symlist {\n    Elf32_Sym *sym; /* symbols */\n    char *str; /* symbol strings */\n    unsigned num; /* number of symbols */\n};\nstruct symtab {\n    struct symlist *st; /* \"static\" symbols */\n    struct symlist *dyn; /* dynamic symbols */\n};\n\nstatic void* xmalloc(size_t size) {\n    void *p;\n    p = malloc(size);\n    if (!p) {\n        printf(\"Out of memory\\n\");\n        exit(1);\n    }\n    return p;\n}\n\nstatic int my_pread(int fd, void *buf, size_t count, off_t offset) {\n    lseek(fd, offset, SEEK_SET);\n    return read(fd, buf, count);\n}\n\nstatic struct symlist* get_syms(int fd, Elf32_Shdr *symh, Elf32_Shdr *strh) {\n    struct symlist *sl, *ret;\n    int rv;\n\n    ret = NULL;\n    sl = (struct symlist *) xmalloc(sizeof(struct symlist));\n    sl->str = NULL;\n    sl->sym = NULL;\n\n    /* sanity */\n    if (symh->sh_size % sizeof(Elf32_Sym)) {\n        //printf(\"elf_error\\n\");\n        goto out;\n    }\n\n    /* symbol table */\n    sl->num = symh->sh_size / sizeof(Elf32_Sym);\n    sl->sym = (Elf32_Sym *) xmalloc(symh->sh_size);\n    rv = my_pread(fd, sl->sym, symh->sh_size, symh->sh_offset);\n    if (0 > rv) {\n        //perror(\"read\");\n        goto out;\n    }\n    if (rv != symh->sh_size) {\n        //printf(\"elf error\\n\");\n        goto out;\n    }\n\n    /* string table */\n    sl->str = (char *) xmalloc(strh->sh_size);\n    rv = my_pread(fd, sl->str, strh->sh_size, strh->sh_offset);\n    if (0 > rv) {\n        //perror(\"read\");\n        goto out;\n    }\n    if (rv != strh->sh_size) {\n        //printf(\"elf error\");\n        goto out;\n    }\n\n    ret = sl;\n    out: return ret;\n}\n\nstatic int do_load(int fd, symtab_t symtab) {\n    int rv;\n    size_t size;\n    Elf32_Ehdr ehdr;\n    Elf32_Shdr *shdr = NULL, *p;\n    Elf32_Shdr *dynsymh, *dynstrh;\n    Elf32_Shdr *symh, *strh;\n    char *shstrtab = NULL;\n    int i;\n    int ret = -1;\n\n    /* elf header */\n    rv = read(fd, &ehdr, sizeof(ehdr));\n    if (0 > rv) {\n        ALOGD(\"read\\n\");\n        goto out;\n    }\n    if (rv != sizeof(ehdr)) {\n        ALOGD(\"elf error 1\\n\");\n        goto out;\n    }\n    if (strncmp((const char *) ELFMAG, (const char *) ehdr.e_ident, SELFMAG)) { /* sanity */\n        ALOGD(\"not an elf\\n\");\n        goto out;\n    }\n    if (sizeof(Elf32_Shdr) != ehdr.e_shentsize) { /* sanity */\n        ALOGD(\"elf error 2\\n\");\n        goto out;\n    }\n\n    /* section header table */\n    size = ehdr.e_shentsize * ehdr.e_shnum;\n    shdr = (Elf32_Shdr *) xmalloc(size);\n    rv = my_pread(fd, shdr, size, ehdr.e_shoff);\n    if (0 > rv) {\n        ALOGD(\"read\\n\");\n        goto out;\n    }\n    if (rv != size) {\n        ALOGD(\"elf error 3 %d %d\\n\", rv, size);\n        goto out;\n    }\n\n    /* section header string table */\n    size = shdr[ehdr.e_shstrndx].sh_size;\n    shstrtab = (char *) xmalloc(size);\n    rv = my_pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset);\n    if (0 > rv) {\n        ALOGD(\"read\\n\");\n        goto out;\n    }\n    if (rv != size) {\n        ALOGD(\"elf error 4 %d %d\\n\", rv, size);\n        goto out;\n    }\n\n    /* symbol table headers */\n    symh = dynsymh = NULL;\n    strh = dynstrh = NULL;\n    for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++)\n        if (SHT_SYMTAB == p->sh_type) {\n            if (symh) {\n                ALOGD(\"too many symbol tables\\n\");\n                goto out;\n            }\n            symh = p;\n        } else if (SHT_DYNSYM == p->sh_type) {\n            if (dynsymh) {\n                ALOGD(\"too many symbol tables\\n\");\n                goto out;\n            }\n            dynsymh = p;\n        } else if (SHT_STRTAB == p->sh_type\n                   && !strncmp(shstrtab + p->sh_name, \".strtab\", 7)) {\n            if (strh) {\n                ALOGD(\"too many string tables\\n\");\n                goto out;\n            }\n            strh = p;\n        } else if (SHT_STRTAB == p->sh_type\n                   && !strncmp(shstrtab + p->sh_name, \".dynstr\", 7)) {\n            if (dynstrh) {\n                ALOGD(\"too many string tables\\n\");\n                goto out;\n            }\n            dynstrh = p;\n        }\n    /* sanity checks */\n    if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) {\n        ALOGD(\"bad dynamic symbol table\\n\");\n        goto out;\n    }\n    if ((!symh && strh) || (symh && !strh)) {\n        ALOGD(\"bad symbol table\\n\");\n        goto out;\n    }\n    if (!dynsymh && !symh) {\n        ALOGD(\"no symbol table\\n\");\n        goto out;\n    }\n\n    /* symbol tables */\n    if (dynsymh)\n        symtab->dyn = get_syms(fd, dynsymh, dynstrh);\n    if (symh)\n        symtab->st = get_syms(fd, symh, strh);\n    ret = 0;\n    out: free(shstrtab);\n    free(shdr);\n    return ret;\n}\n\nstatic symtab_t load_symtab(char *filename) {\n    int fd;\n    symtab_t symtab;\n\n    symtab = (symtab_t) xmalloc(sizeof(*symtab));\n    memset(symtab, 0, sizeof(*symtab));\n\n    fd = open(filename, O_RDONLY);\n    if (0 > fd) {\n        ALOGE(\"%s open\\n\", __func__);\n        return NULL;\n    }\n    if (0 > do_load(fd, symtab)) {\n        ALOGE(\"Error ELF parsing %s\\n\", filename);\n        free(symtab);\n        symtab = NULL;\n    }\n    close(fd);\n    return symtab;\n}\n\n\nstatic int load_memmap(pid_t pid, struct mm *mm, int *nmmp) {\n    size_t buf_size = 0x40000;\n    char *p_buf = (char *) malloc(buf_size); // increase this if needed for larger \"maps\"\n    char name[MAX_NAME_LEN] = { 0 };\n    char *p;\n    unsigned long start, end;\n    struct mm *m;\n    int nmm = 0;\n    int fd, rv;\n    int i;\n\n    sprintf(p_buf, \"/proc/%d/maps\", pid);\n    fd = open(p_buf, O_RDONLY);\n    if (0 > fd) {\n        ALOGE(\"Can't open %s for reading\\n\", p_buf);\n        free(p_buf);\n        return -1;\n    }\n\n    /* Zero to ensure data is null terminated */\n    memset(p_buf, 0, buf_size);\n\n    p = p_buf;\n    while (1) {\n        rv = read(fd, p, buf_size - (p - p_buf));\n        if (0 > rv) {\n            ALOGE(\"%s read\", __FUNCTION__);\n            free(p_buf);\n            return -1;\n        }\n        if (0 == rv)\n            break;\n        p += rv;\n        if (p - p_buf >= buf_size) {\n            ALOGE(\"Too many memory mapping\\n\");\n            free(p_buf);\n            return -1;\n        }\n    }\n    close(fd);\n\n    p = strtok(p_buf, \"\\n\");\n    m = mm;\n    while (p) {\n        /* parse current map line */\n        rv = sscanf(p, \"%08lx-%08lx %*s %*s %*s %*s %s\\n\", &start, &end, name);\n\n        p = strtok(NULL, \"\\n\");\n\n        if (rv == 2) {\n            m = &mm[nmm++];\n            m->start = start;\n            m->end = end;\n            memcpy(m->name, MEMORY_ONLY, sizeof(MEMORY_ONLY));\n            continue;\n        }\n\n        /* search backward for other mapping with same name */\n        for (i = nmm - 1; i >= 0; i--) {\n            m = &mm[i];\n            if (!strcmp(m->name, name))\n                break;\n        }\n\n        if (i >= 0) {\n            if (start < m->start)\n                m->start = start;\n            if (end > m->end)\n                m->end = end;\n        } else {\n            /* new entry */\n            m = &mm[nmm++];\n            m->start = start;\n            m->end = end;\n            memcpy(m->name, name, strlen(name));\n        }\n    }\n\n    *nmmp = nmm;\n    free(p_buf);\n    return 0;\n}\n\n/* Find libc in MM, storing no more than LEN-1 chars of\n its name in NAME and set START to its starting\n address.  If libc cannot be found return -1 and\n leave NAME and START untouched.  Otherwise return 0\n and null-terminated NAME. */\nstatic int find_libname(const char *libn, char *name, int len, unsigned long *start,\n                        struct mm *mm, int nmm) {\n    int i;\n    struct mm *m;\n    char *p;\n    for (i = 0, m = mm; i < nmm; i++, m++) {\n        if (!strcmp(m->name, MEMORY_ONLY))\n            continue;\n        p = strrchr(m->name, '/');\n        if (!p)\n            continue;\n        p++;\n        if (strncmp(libn, p, strlen(libn)))\n            continue;\n        p += strlen(libn);\n\n        /* here comes our crude test -> 'libc.so' or 'libc-[0-9]' */\n        if (!strncmp(\"so\", p, 2) || 1) // || (p[0] == '-' && isdigit(p[1])))\n            break;\n    }\n    if (i >= nmm)\n        /* not found */\n        return -1;\n\n    *start = m->start;\n    strncpy(name, m->name, len);\n    if (strlen(m->name) >= len)\n        name[len - 1] = '\\0';\n\n    mprotect((void*) m->start, m->end - m->start,\n             PROT_READ | PROT_WRITE | PROT_EXEC);\n    return 0;\n}\n\nstatic int lookup2(struct symlist *sl, unsigned char type, char *name,\n                   unsigned long *val) {\n    Elf32_Sym *p;\n    int len;\n    int i;\n\n    len = strlen(name);\n    for (i = 0, p = sl->sym; i < sl->num; i++, p++) {\n        //ALOGD(\"name: %s %x\\n\", sl->str+p->st_name, p->st_value)\n        if (!strncmp(sl->str + p->st_name, name, len)\n            && *(sl->str + p->st_name + len) == 0\n            && ELF32_ST_TYPE(p->st_info) == type) {\n            //if (p->st_value != 0) {\n            *val = p->st_value;\n            return 0;\n            //}\n        }\n    }\n    return -1;\n}\n\nstatic int lookup_sym(symtab_t s, unsigned char type, char *name,\n                      unsigned long *val) {\n    if (s->dyn && !lookup2(s->dyn, type, name, val))\n        return 0;\n    if (s->st && !lookup2(s->st, type, name, val))\n        return 0;\n    return -1;\n}\n\nstatic int lookup_func_sym(symtab_t s, char *name, unsigned long *val) {\n    return lookup_sym(s, STT_FUNC, name, val);\n}\n\nint find_name(pid_t pid, const char *name, const char *libn,\n              unsigned long *addr) {\n    struct mm mm[1000] = { 0 };\n    unsigned long libcaddr;\n    int nmm;\n    char libc[1024] = { 0 };\n    symtab_t s;\n\n    if (0 > load_memmap(pid, mm, &nmm)) {\n        ALOGD(\"cannot read memory map\\n\");\n        return -1;\n    }\n    if (0\n        > find_libname((char *) libn, (char *) libc, sizeof(libc),\n                       &libcaddr, mm, nmm)) {\n        ALOGD(\"cannot find lib: %s\\n\", libn);\n        return -1;\n    }\n    //ALOGD(\"lib: >%s<\\n\", libc)\n    s = load_symtab(libc);\n    if (!s) {\n        ALOGD(\"cannot read symbol table\\n\");\n        return -1;\n    }\n    if (0 > lookup_func_sym(s, (char *) name, addr)) {\n        ALOGD(\"cannot find function: %s\\n\", name);\n        return -1;\n    }\n    *addr += libcaddr;\n    return 0;\n}\n\nint find_libbase(pid_t pid, const char *libn, unsigned long *addr) {\n    struct mm mm[1000] = { 0 };\n    unsigned long libcaddr;\n    int nmm;\n    char libc[1024] = { 0 };\n    symtab_t s;\n\n    if (0 > load_memmap(pid, mm, &nmm)) {\n        ALOGD(\"cannot read memory map\\n\");\n        return -1;\n    }\n    if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) {\n        ALOGD(\"cannot find lib\\n\");\n        return -1;\n    }\n    *addr = libcaddr;\n    return 0;\n}"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/SymbolFinder.h",
    "content": "#ifndef SYMBOL_FINDER\n#define SYMBOL_FINDER\n\n#include <unistd.h>\n\nextern int find_name(pid_t pid, const char *name,const  char *libn, unsigned long *addr);\nextern int find_libbase(pid_t pid, const char *libn, unsigned long *addr);\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/VMPatch.cpp",
    "content": "//\n// VirtualApp Native Project\n//\n#include <Jni/VAJni.h>\n#include <Substrate/CydiaSubstrate.h>\n#include \"VMPatch.h\"\n#include \"fake_dlfcn.h\"\n\nnamespace FunctionDef {\n    typedef void (*Function_DalvikBridgeFunc)(const void **, void *, const void *, void *);\n\n    typedef jobject (*Function_openDexNativeFunc)(JNIEnv *, jclass, jstring, jstring, jint);\n\n    typedef jobject (*Native_openDexNativeFunc_N)(JNIEnv *, jclass, jstring, jstring, jint, jobject,\n                                                  jobject);\n\n\n    typedef jint (*Function_cameraNativeSetupFunc_T1)(JNIEnv *, jobject, jobject, jint, jstring);\n\n    typedef jint (*Function_cameraNativeSetupFunc_T2)(JNIEnv *, jobject, jobject, jint, jint,\n                                                      jstring);\n\n    typedef jint (*Function_cameraNativeSetupFunc_T3)(JNIEnv *, jobject, jobject, jint, jint,\n                                                      jstring,\n                                                      jboolean);\n\n    typedef jint (*Function_cameraNativeSetupFunc_T4)(JNIEnv *, jobject, jobject, jint, jstring,\n                                                      jboolean);\n\n    typedef jint (*Function_getCallingUid)(JNIEnv *, jclass);\n\n    typedef jint (*Function_audioRecordNativeCheckPermission)(JNIEnv *, jobject, jstring);\n}\n\nusing namespace FunctionDef;\n\n\nstatic struct {\n\n    bool is_art;\n    int native_offset;\n    char *host_packageName;\n    jint api_level;\n    jmethodID method_onGetCallingUid;\n    jmethodID method_onOpenDexFileNative;\n\n    void *art_work_around_app_jni_bugs;\n\n    char *(*GetCstrFromString)(void *);\n\n    void *(*GetStringFromCstr)(const char *);\n\n    int (*native_getCallingUid)(int);\n\n    int (*IPCThreadState_self)(void);\n\n    Function_getCallingUid jni_orig_getCallingUid;\n    Function_DalvikBridgeFunc orig_cameraNativeSetup_dvm;\n\n    int cameraMethodType;\n    union {\n        Function_cameraNativeSetupFunc_T1 t1;\n        Function_cameraNativeSetupFunc_T2 t2;\n        Function_cameraNativeSetupFunc_T3 t3;\n        Function_cameraNativeSetupFunc_T4 t4;\n    } orig_native_cameraNativeSetupFunc;\n\n    Function_DalvikBridgeFunc orig_openDexFile_dvm;\n    union {\n        Function_openDexNativeFunc beforeN;\n        Native_openDexNativeFunc_N afterN;\n    } orig_openDexNativeFunc_art;\n\n    Function_audioRecordNativeCheckPermission orig_audioRecordNativeCheckPermission;\n\n} patchEnv;\n\n\njint getCallingUid(alias_ref<jclass> clazz) {\n    jint uid;\n    if (patchEnv.is_art) {\n        uid = patchEnv.jni_orig_getCallingUid(Environment::ensureCurrentThreadIsAttached(),\n                                              clazz.get());\n    } else {\n        uid = patchEnv.native_getCallingUid(patchEnv.IPCThreadState_self());\n    }\n    uid = Environment::ensureCurrentThreadIsAttached()->CallStaticIntMethod(nativeEngineClass.get(),\n                                                                            patchEnv.method_onGetCallingUid,\n                                                                            uid);\n    return uid;\n}\n\n\nstatic jobject new_native_openDexNativeFunc(JNIEnv *env, jclass jclazz, jstring javaSourceName,\n                                            jstring javaOutputName, jint options) {\n    jclass stringClass = env->FindClass(\"java/lang/String\");\n    jobjectArray array = env->NewObjectArray(2, stringClass, NULL);\n\n    if (javaSourceName) {\n        env->SetObjectArrayElement(array, 0, javaSourceName);\n    }\n    if (javaOutputName) {\n        env->SetObjectArrayElement(array, 1, javaOutputName);\n    }\n    env->CallStaticVoidMethod(nativeEngineClass.get(), patchEnv.method_onOpenDexFileNative, array);\n\n    jstring newSource = (jstring) env->GetObjectArrayElement(array, 0);\n    jstring newOutput = (jstring) env->GetObjectArrayElement(array, 1);\n\n    return patchEnv.orig_openDexNativeFunc_art.beforeN(env, jclazz, newSource, newOutput,\n                                                       options);\n}\n\nstatic jobject new_native_openDexNativeFunc_N(JNIEnv *env, jclass jclazz, jstring javaSourceName,\n                                              jstring javaOutputName, jint options, jobject loader,\n                                              jobject elements) {\n    jclass stringClass = env->FindClass(\"java/lang/String\");\n    jobjectArray array = env->NewObjectArray(2, stringClass, NULL);\n\n    if (javaSourceName) {\n        env->SetObjectArrayElement(array, 0, javaSourceName);\n    }\n    if (javaOutputName) {\n        env->SetObjectArrayElement(array, 1, javaOutputName);\n    }\n    env->CallStaticVoidMethod(nativeEngineClass.get(), patchEnv.method_onOpenDexFileNative, array);\n\n    jstring newSource = (jstring) env->GetObjectArrayElement(array, 0);\n    jstring newOutput = (jstring) env->GetObjectArrayElement(array, 1);\n\n    return patchEnv.orig_openDexNativeFunc_art.afterN(env, jclazz, newSource, newOutput, options,\n                                                      loader, elements);\n}\n\n\nstatic void\nnew_bridge_openDexNativeFunc(const void **args, void *pResult, const void *method, void *self) {\n\n    JNIEnv *env = Environment::ensureCurrentThreadIsAttached();\n\n    const char *source = args[0] == NULL ? NULL : patchEnv.GetCstrFromString((void *) args[0]);\n    const char *output = args[1] == NULL ? NULL : patchEnv.GetCstrFromString((void *) args[1]);\n\n    jstring orgSource = source == NULL ? NULL : env->NewStringUTF(source);\n    jstring orgOutput = output == NULL ? NULL : env->NewStringUTF(output);\n\n    jclass stringClass = env->FindClass(\"java/lang/String\");\n    jobjectArray array = env->NewObjectArray(2, stringClass, NULL);\n    if (orgSource) {\n        env->SetObjectArrayElement(array, 0, orgSource);\n    }\n    if (orgOutput) {\n        env->SetObjectArrayElement(array, 1, orgOutput);\n    }\n    env->CallStaticVoidMethod(nativeEngineClass.get(), patchEnv.method_onOpenDexFileNative, array);\n\n    jstring newSource = (jstring) env->GetObjectArrayElement(array, 0);\n    jstring newOutput = (jstring) env->GetObjectArrayElement(array, 1);\n\n    const char *_newSource = newSource == NULL ? NULL : env->GetStringUTFChars(newSource, NULL);\n    const char *_newOutput = newOutput == NULL ? NULL : env->GetStringUTFChars(newOutput, NULL);\n\n    args[0] = _newSource == NULL ? NULL : patchEnv.GetStringFromCstr(_newSource);\n    args[1] = _newOutput == NULL ? NULL : patchEnv.GetStringFromCstr(_newOutput);\n\n    if (source && orgSource) {\n        env->ReleaseStringUTFChars(orgSource, source);\n    }\n    if (output && orgOutput) {\n        env->ReleaseStringUTFChars(orgOutput, output);\n    }\n\n    patchEnv.orig_openDexFile_dvm(args, pResult, method, self);\n}\n\nstatic jint new_native_cameraNativeSetupFunc_T1(JNIEnv *env, jobject thiz, jobject camera_this,\n                                                jint cameraId, jstring packageName) {\n\n    jstring host = env->NewStringUTF(patchEnv.host_packageName);\n\n    return patchEnv.orig_native_cameraNativeSetupFunc.t1(env, thiz, camera_this,\n                                                         cameraId,\n                                                         host);\n}\n\nstatic jint new_native_cameraNativeSetupFunc_T2(JNIEnv *env, jobject thiz, jobject camera_this,\n                                                jint cameraId, jint halVersion,\n                                                jstring packageName) {\n\n    jstring host = env->NewStringUTF(patchEnv.host_packageName);\n\n    return patchEnv.orig_native_cameraNativeSetupFunc.t2(env, thiz, camera_this, cameraId,\n                                                         halVersion, host);\n}\n\nstatic jint new_native_cameraNativeSetupFunc_T3(JNIEnv *env, jobject thiz, jobject camera_this,\n                                                jint cameraId, jint halVersion,\n                                                jstring packageName, jboolean option) {\n\n    jstring host = env->NewStringUTF(patchEnv.host_packageName);\n\n    return patchEnv.orig_native_cameraNativeSetupFunc.t3(env, thiz, camera_this, cameraId,\n                                                         halVersion, host, option);\n}\n\nstatic jint new_native_cameraNativeSetupFunc_T4(JNIEnv *env, jobject thiz, jobject camera_this,\n                                                jint cameraId,\n                                                jstring packageName, jboolean option) {\n\n    jstring host = env->NewStringUTF(patchEnv.host_packageName);\n\n    return patchEnv.orig_native_cameraNativeSetupFunc.t4(env, thiz, camera_this, cameraId, host,\n                                                         option);\n}\n\n\nstatic jint\nnew_native_audioRecordNativeCheckPermission(JNIEnv *env, jobject thiz, jstring _packagename) {\n    jstring host = env->NewStringUTF(patchEnv.host_packageName);\n    return patchEnv.orig_audioRecordNativeCheckPermission(env, thiz, host);\n}\n\n\nstatic void\nnew_bridge_cameraNativeSetupFunc(const void **args, void *pResult, const void *method, void *self) {\n    // args[0] = this\n    switch (patchEnv.cameraMethodType) {\n        case 1:\n            args[4] = patchEnv.GetStringFromCstr(patchEnv.host_packageName);\n            break;\n        case 2:\n            args[5] = patchEnv.GetStringFromCstr(patchEnv.host_packageName);\n            break;\n        case 3:\n            args[5] = patchEnv.GetStringFromCstr(patchEnv.host_packageName);\n            break;\n        case 4:\n            args[4] = patchEnv.GetStringFromCstr(patchEnv.host_packageName);\n            break;\n    }\n    patchEnv.orig_cameraNativeSetup_dvm(args, pResult, method, self);\n}\n\nvoid mark() {\n    // Do nothing\n};\n\nstatic size_t getArtMethodAddress(jobject javaMethod, jmethodID methodId) {\n    if (patchEnv.api_level < 30) {\n        return (size_t) methodId;\n    } else {\n        JNIEnv *env = Environment::current();\n        jclass executableClass = env->FindClass(\"java/lang/reflect/Executable\");\n        jfieldID artMethod = env->GetFieldID(executableClass, \"artMethod\", \"J\");\n        jlong addr = env->GetLongField(javaMethod, artMethod);\n        return addr;\n    }\n}\n\nvoid measureNativeOffset(bool isArt) {\n\n    jmethodID markMethod = nativeEngineClass->getStaticMethod<void(void)>(\"nativeMark\").getId();\n\n    jobject method = Environment::current()->ToReflectedMethod(nativeEngineClass.get(), markMethod, JNI_TRUE);\n    size_t startAddress = (size_t) getArtMethodAddress(method, markMethod);\n    size_t targetAddress = (size_t) mark;\n    if (isArt && patchEnv.art_work_around_app_jni_bugs) {\n        targetAddress = (size_t) patchEnv.art_work_around_app_jni_bugs;\n    }\n\n    int offset = 0;\n    bool found = false;\n    while (true) {\n        if (*((size_t *) (startAddress + offset)) == targetAddress) {\n            found = true;\n            break;\n        }\n        offset += 4;\n        if (offset >= 100) {\n            ALOGE(\"Error: Unable to find the jni function.\");\n            break;\n        }\n    }\n    if (found) {\n        patchEnv.native_offset = offset;\n        if (!isArt) {\n            patchEnv.native_offset += (sizeof(int) + sizeof(void *));\n        }\n    }\n}\n\n\ninline void replaceGetCallingUid(jboolean isArt) {\n    auto binderClass = findClassLocal(\"android/os/Binder\");\n    if (isArt) {\n        size_t mtd_getCallingUid = (size_t) binderClass->getStaticMethod<jint(void)>(\n                \"getCallingUid\").getId();\n        int nativeFuncOffset = patchEnv.native_offset;\n        void **jniFuncPtr = (void **) (mtd_getCallingUid + nativeFuncOffset);\n        patchEnv.jni_orig_getCallingUid = (Function_getCallingUid) (*jniFuncPtr);\n        *jniFuncPtr = (void *) getCallingUid;\n    } else {\n        binderClass->registerNatives({makeNativeMethod(\"getCallingUid\", getCallingUid)});\n    }\n}\n\ninline void\nreplaceOpenDexFileMethod(jobject javaMethod, jboolean isArt, int apiLevel) {\n    jmethodID openDexNative = Environment::current()->FromReflectedMethod(javaMethod);\n    size_t mtd_openDexNative = getArtMethodAddress(javaMethod, openDexNative);\n    int nativeFuncOffset = patchEnv.native_offset;\n    void **jniFuncPtr = (void **) (mtd_openDexNative + nativeFuncOffset);\n\n    if (!isArt) {\n        patchEnv.orig_openDexFile_dvm = (Function_DalvikBridgeFunc) (*jniFuncPtr);\n        *jniFuncPtr = (void *) new_bridge_openDexNativeFunc;\n    } else {\n        if (apiLevel < 24) {\n            patchEnv.orig_openDexNativeFunc_art.beforeN = (Function_openDexNativeFunc) (*jniFuncPtr);\n            *jniFuncPtr = (void *) new_native_openDexNativeFunc;\n        } else {\n            patchEnv.orig_openDexNativeFunc_art.afterN = (Native_openDexNativeFunc_N) (*jniFuncPtr);\n            *jniFuncPtr = (void *) new_native_openDexNativeFunc_N;\n        }\n    }\n\n}\n\n\ninline void\nreplaceCameraNativeSetupMethod(jobject javaMethod, jboolean isArt, int apiLevel) {\n\n    if (!javaMethod) {\n        return;\n    }\n    jmethodID cameraNativeSetup = Environment::current()->FromReflectedMethod(javaMethod);\n    size_t mtd_cameraNativeSetup = getArtMethodAddress(javaMethod, cameraNativeSetup);\n    int nativeFuncOffset = patchEnv.native_offset;\n    void **jniFuncPtr = (void **) (mtd_cameraNativeSetup + nativeFuncOffset);\n\n    if (!isArt) {\n        patchEnv.orig_cameraNativeSetup_dvm = (Function_DalvikBridgeFunc) (*jniFuncPtr);\n        *jniFuncPtr = (void *) new_bridge_cameraNativeSetupFunc;\n    } else {\n        switch (patchEnv.cameraMethodType) {\n            case 1:\n                patchEnv.orig_native_cameraNativeSetupFunc.t1 = (Function_cameraNativeSetupFunc_T1) (*jniFuncPtr);\n                *jniFuncPtr = (void *) new_native_cameraNativeSetupFunc_T1;\n                break;\n            case 2:\n                patchEnv.orig_native_cameraNativeSetupFunc.t2 = (Function_cameraNativeSetupFunc_T2) (*jniFuncPtr);\n                *jniFuncPtr = (void *) new_native_cameraNativeSetupFunc_T2;\n                break;\n            case 3:\n                patchEnv.orig_native_cameraNativeSetupFunc.t3 = (Function_cameraNativeSetupFunc_T3) (*jniFuncPtr);\n                *jniFuncPtr = (void *) new_native_cameraNativeSetupFunc_T3;\n                break;\n            case 4:\n                patchEnv.orig_native_cameraNativeSetupFunc.t4 = (Function_cameraNativeSetupFunc_T4) (*jniFuncPtr);\n                *jniFuncPtr = (void *) new_native_cameraNativeSetupFunc_T4;\n                break;\n        }\n    }\n\n}\n\n\nvoid\nreplaceAudioRecordNativeCheckPermission(jobject javaMethod, jboolean isArt, int api) {\n    if (!javaMethod || !isArt) {\n        return;\n    }\n    jmethodID methodStruct = Environment::current()->FromReflectedMethod(javaMethod);\n    size_t mtd_methodStruct = getArtMethodAddress(javaMethod, methodStruct);\n    void **funPtr = (void **) (mtd_methodStruct + patchEnv.native_offset);\n    patchEnv.orig_audioRecordNativeCheckPermission = (Function_audioRecordNativeCheckPermission) (*funPtr);\n    *funPtr = (void *) new_native_audioRecordNativeCheckPermission;\n}\n\n\n/**\n * Only called once.\n * @param javaMethod Method from Java\n * @param isArt Dalvik or Art\n * @param apiLevel Api level from Java\n */\nvoid hookAndroidVM(JArrayClass<jobject> javaMethods,\n                   jstring packageName, jboolean isArt, jint apiLevel,\n                   jint cameraMethodType) {\n\n    JNIEnv *env = Environment::current();\n\n    JNINativeMethod methods[] = {\n            NATIVE_METHOD((void *) mark, \"nativeMark\", \"()V\"),\n    };\n    if (env->RegisterNatives(nativeEngineClass.get(), methods, 1) < 0) {\n        return;\n    }\n    patchEnv.is_art = isArt;\n    patchEnv.cameraMethodType = cameraMethodType;\n    patchEnv.host_packageName = (char *) env->GetStringUTFChars(packageName,\n                                                                NULL);\n    patchEnv.api_level = apiLevel;\n    void *soInfo = getDvmOrArtSOHandle();\n    patchEnv.method_onGetCallingUid = nativeEngineClass->getStaticMethod<jint(jint)>(\n            \"onGetCallingUid\").getId();\n    patchEnv.method_onOpenDexFileNative = env->GetStaticMethodID(nativeEngineClass.get(),\n                                                                 \"onOpenDexFileNative\",\n                                                                 \"([Ljava/lang/String;)V\");\n\n    if (isArt) {\n        patchEnv.art_work_around_app_jni_bugs = dlsym(soInfo, \"art_work_around_app_jni_bugs\");\n    } else {\n        // workaround for dlsym returns null when system has libhoudini\n        void *h = dlopen(\"/system/lib/libandroid_runtime.so\", RTLD_LAZY);\n        {\n            patchEnv.IPCThreadState_self = (int (*)(void)) dlsym(RTLD_DEFAULT,\n                                                                 \"_ZN7android14IPCThreadState4selfEv\");\n            patchEnv.native_getCallingUid = (int (*)(int)) dlsym(RTLD_DEFAULT,\n                                                                 \"_ZNK7android14IPCThreadState13getCallingUidEv\");\n            if (patchEnv.IPCThreadState_self == NULL) {\n                patchEnv.IPCThreadState_self = (int (*)(void)) dlsym(RTLD_DEFAULT,\n                                                                     \"_ZN7android14IPCThreadState13getCallingUidEv\");\n            }\n        }\n        if (h != NULL) {\n            dlclose(h);\n        }\n\n        patchEnv.GetCstrFromString = (char *(*)(void *)) dlsym(soInfo,\n                                                               \"_Z23dvmCreateCstrFromStringPK12StringObject\");\n        if (!patchEnv.GetCstrFromString) {\n            patchEnv.GetCstrFromString = (char *(*)(void *)) dlsym(soInfo,\n                                                                   \"dvmCreateCstrFromString\");\n        }\n        patchEnv.GetStringFromCstr = (void *(*)(const char *)) dlsym(soInfo,\n                                                                     \"_Z23dvmCreateStringFromCstrPKc\");\n        if (!patchEnv.GetStringFromCstr) {\n            patchEnv.GetStringFromCstr = (void *(*)(const char *)) dlsym(soInfo,\n                                                                         \"dvmCreateStringFromCstr\");\n        }\n    }\n    measureNativeOffset(isArt);\n    replaceGetCallingUid(isArt);\n\n    replaceOpenDexFileMethod(javaMethods.getElement(OPEN_DEX).get(), isArt,\n                             apiLevel);\n    replaceCameraNativeSetupMethod(javaMethods.getElement(CAMERA_SETUP).get(),\n                                   isArt, apiLevel);\n    replaceAudioRecordNativeCheckPermission(javaMethods.getElement(\n            AUDIO_NATIVE_CHECK_PERMISSION).get(),\n                                            isArt, apiLevel);\n}\n\nbool processNothing(void* thiz, void* new_methods){ return true; }\nbool (*orig_ProcessProfilingInfo)(void*, void*);\n\nbool compileNothing(void* thiz, void* thread, void* method, bool osr) { return false; }\nbool (*orig_CompileNothing)(void* thiz, void* thread, void* method, bool osr);\n\nvoid (*org_notifyJitActivity)(void *);\nvoid notifyNothing(void *thiz) {\n    return;\n}\n\nvoid disableJit(int apiLevel) {\n#ifdef __arm__\n    void *libart = fake_dlopen(\"/system/lib/libart.so\", RTLD_NOW);\n    if (libart) {\n        // disable profile.\n        void *processProfilingInfo = NULL;\n        const char *processProfileInfoFunc =\n                apiLevel < 26 ? \"_ZN3art12ProfileSaver20ProcessProfilingInfoEPt\" :\n                \"_ZN3art12ProfileSaver20ProcessProfilingInfoEbPt\";\n        processProfilingInfo = fake_dlsym(libart, processProfileInfoFunc);\n        ALOGE(\"processProfileingInfo: %p\", processProfilingInfo);\n        if (processProfilingInfo) {\n            MSHookFunction(processProfilingInfo, (void*)processNothing, (void**)&orig_ProcessProfilingInfo);\n        }\n\n        // disable jit\n        void *compileMethod = NULL;\n        compileMethod = fake_dlsym(libart,\n                                   \"_ZN3art3jit3Jit13CompileMethodEPNS_9ArtMethodEPNS_6ThreadEb\");\n        ALOGE(\"compileMethod: %p\", compileMethod);\n        if (compileMethod) {\n            MSHookFunction(compileMethod, (void*) compileNothing, (void**) &orig_CompileNothing);\n        }\n\n        void *notifyJitActivity = fake_dlsym(libart, \"_ZN3art12ProfileSaver17NotifyJitActivityEv\");\n        if (notifyJitActivity) {\n            MSHookFunction(notifyJitActivity, (void *) notifyNothing,\n                          (void **) &org_notifyJitActivity);\n        }\n    }\n#endif\n}\n\nvoid *getDvmOrArtSOHandle() {\n    char so_name[25] = {0};\n    __system_property_get(\"persist.sys.dalvik.vm.lib.2\", so_name);\n    if (strlen(so_name) == 0) {\n        __system_property_get(\"persist.sys.dalvik.vm.lib\", so_name);\n    }\n    void *soInfo = dlopen(so_name, 0);\n    if (!soInfo) {\n        soInfo = RTLD_DEFAULT;\n    }\n    return soInfo;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/VMPatch.h",
    "content": "//\n// VirtualApp Native Project\n//\n\n#ifndef FOUNDATION_PATH\n#define FOUNDATION_PATH\n\n\n#include <jni.h>\n#include <dlfcn.h>\n#include <stddef.h>\n#include <fcntl.h>\n#include <sys/system_properties.h>\n#include <fb/include/fb/ALog.h>\n#include <fb/include/fb/fbjni.h>\n#include \"Jni/Helper.h\"\n\nusing namespace facebook::jni;\n\nenum METHODS {\n    OPEN_DEX = 0, CAMERA_SETUP, AUDIO_NATIVE_CHECK_PERMISSION\n};\n\nvoid hookAndroidVM(JArrayClass<jobject> javaMethods,\n                   jstring packageName, jboolean isArt, jint apiLevel, jint cameraMethodType);\n\nvoid *getDvmOrArtSOHandle();\n\nvoid disableJit(int apiLevel);\n\n#endif //NDK_HOOK_NATIVE_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/fake_dlfcn.cpp",
    "content": "// Copyright (c) 2016 avs333\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n//\t\tof this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n//\t\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//\t\tcopies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n//\t\tThe above copyright notice and this permission notice shall be included in all\n//\t\tcopies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// \t\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n#include <stdio.h>\n#include <fcntl.h>\n#include <sys/mman.h>\n#include <elf.h>\n#include <android/log.h>\n#include \"fake_dlfcn.h\"\n\n#define TAG_NAME\t\"fake_dlfcn\"\n\n#define log_info(fmt,args...) __android_log_print(ANDROID_LOG_INFO, TAG_NAME, (const char *) fmt, ##args)\n#define log_err(fmt,args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, (const char *) fmt, ##args)\n\n//#ifdef LOG_DBG\n//#define log_dbg log_info\n//#else\n#define log_dbg(...)\n#define log_info(...)\n//#define log_err(...)\n//#endif\n\n#ifdef __arm__\n#define Elf_Ehdr Elf32_Ehdr\n#define Elf_Shdr Elf32_Shdr\n#define Elf_Sym  Elf32_Sym\n#elif defined(__aarch64__) || defined(__x86_64__)\n#define Elf_Ehdr Elf64_Ehdr\n#define Elf_Shdr Elf64_Shdr\n#define Elf_Sym  Elf64_Sym\n#elif  defined(__i386__)\n#define Elf_Ehdr Elf32_Ehdr\n#define Elf_Shdr Elf32_Shdr\n#define Elf_Sym  Elf32_Sym\n#else\n//#error \"Arch unknown, please port me\"\n#endif\n\nstruct ctx {\n\tvoid *load_addr;\n\tvoid *dynstr;\n\tvoid *dynsym;\n\tint nsyms;\n\toff_t bias;\n};\n\nextern \"C\" {\nint fake_dlclose(void *handle) {\n\tif (handle) {\n\t\tstruct ctx *ctx = (struct ctx *) handle;\n\t\tif (ctx->dynsym) free(ctx->dynsym);    /* we're saving dynsym and dynstr */\n\t\tif (ctx->dynstr) free(ctx->dynstr);    /* from library file just in case */\n\t\tfree(ctx);\n\t}\n\treturn 0;\n}\n\n/* flags are ignored */\n\nvoid *fake_dlopen(const char *libpath, int flags) {\n\tFILE *maps;\n\tchar buff[256];\n\tstruct ctx *ctx = 0;\n\toff_t load_addr, size;\n\tint k, fd = -1, found = 0;\n\tvoid *shoff;\n\tElf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED;\n\n#define fatal(fmt, args...) do { log_err(fmt,##args); goto err_exit; } while(0)\n\n\tmaps = fopen(\"/proc/self/maps\", \"r\");\n\tif (!maps) fatal(\"failed to open maps\");\n\n\twhile (!found && fgets(buff, sizeof(buff), maps))\n\t\tif (strstr(buff, \"r-xp\") && strstr(buff, libpath)) found = 1;\n\n\tfclose(maps);\n\n\tif (!found) fatal(\"%s not found in my userspace\", libpath);\n\n\tif (sscanf(buff, \"%lx\", &load_addr) != 1)\n\t\tfatal(\"failed to read load address for %s\", libpath);\n\n\tlog_info(\"%s loaded in Android at 0x%08lx\", libpath, load_addr);\n\n\t/* Now, mmap the same library once again */\n\n\tfd = open(libpath, O_RDONLY);\n\tif (fd < 0) fatal(\"failed to open %s\", libpath);\n\n\tsize = lseek(fd, 0, SEEK_END);\n\tif (size <= 0) fatal(\"lseek() failed for %s\", libpath);\n\n\telf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);\n\tclose(fd);\n\tfd = -1;\n\n\tif (elf == MAP_FAILED) fatal(\"mmap() failed for %s\", libpath);\n\n\tctx = (struct ctx *) calloc(1, sizeof(struct ctx));\n\tif (!ctx) fatal(\"no memory for %s\", libpath);\n\n\tctx->load_addr = (void *) load_addr;\n\tshoff = ((char *) elf) + elf->e_shoff;\n\n\tfor (k = 0; k < elf->e_shnum; k++, shoff = (char*)shoff + elf->e_shentsize) {\n\n\t\tElf_Shdr *sh = (Elf_Shdr *) shoff;\n\t\tlog_dbg(\"%s: k=%d shdr=%p type=%x\", __func__, k, sh, sh->sh_type);\n\n\t\tswitch (sh->sh_type) {\n\n\t\t\tcase SHT_DYNSYM:\n\t\t\t\tif (ctx->dynsym) fatal(\"%s: duplicate DYNSYM sections\", libpath); /* .dynsym */\n\t\t\t\tctx->dynsym = malloc(sh->sh_size);\n\t\t\t\tif (!ctx->dynsym) fatal(\"%s: no memory for .dynsym\", libpath);\n\t\t\t\tmemcpy(ctx->dynsym, ((char *) elf) + sh->sh_offset, sh->sh_size);\n\t\t\t\tctx->nsyms = (sh->sh_size / sizeof(Elf_Sym));\n\t\t\t\tbreak;\n\n\t\t\tcase SHT_STRTAB:\n\t\t\t\tif (ctx->dynstr) break;    /* .dynstr is guaranteed to be the first STRTAB */\n\t\t\t\tctx->dynstr = malloc(sh->sh_size);\n\t\t\t\tif (!ctx->dynstr) fatal(\"%s: no memory for .dynstr\", libpath);\n\t\t\t\tmemcpy(ctx->dynstr, ((char *) elf) + sh->sh_offset, sh->sh_size);\n\t\t\t\tbreak;\n\n\t\t\tcase SHT_PROGBITS:\n\t\t\t\tif (!ctx->dynstr || !ctx->dynsym) break;\n\t\t\t\t/* won't even bother checking against the section name */\n\t\t\t\tctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset;\n\t\t\t\tk = elf->e_shnum;  /* exit for */\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tmunmap(elf, size);\n\telf = 0;\n\n\tif (!ctx->dynstr || !ctx->dynsym) fatal(\"dynamic sections not found in %s\", libpath);\n\n#undef fatal\n\n\tlog_dbg(\"%s: ok, dynsym = %p, dynstr = %p\", libpath, ctx->dynsym, ctx->dynstr);\n\n\treturn ctx;\n\n\terr_exit:\n\tif (fd >= 0) close(fd);\n\tif (elf != MAP_FAILED) munmap(elf, size);\n\tfake_dlclose(ctx);\n\treturn 0;\n}\n\nvoid *fake_dlsym(void *handle, const char *name) {\n\tint k;\n\tstruct ctx *ctx = (struct ctx *) handle;\n\tElf_Sym *sym = (Elf_Sym *) ctx->dynsym;\n\tchar *strings = (char *) ctx->dynstr;\n\n\tfor (k = 0; k < ctx->nsyms; k++, sym++)\n\t\tif (strcmp(strings + sym->st_name, name) == 0) {\n\t\t\t/*  NB: sym->st_value is an offset into the section for relocatables,\n            but a VMA for shared libs or exe files, so we have to subtract the bias */\n\t\t\tvoid *ret = (char*)ctx->load_addr + sym->st_value - ctx->bias;\n\t\t\tlog_info(\"%s found at %p\", name, ret);\n\t\t\treturn ret;\n\t\t}\n\treturn 0;\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Foundation/fake_dlfcn.h",
    "content": "// Copyright (c) 2016 avs333\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n//\t\tof this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n//\t\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//\t\tcopies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n//\t\tThe above copyright notice and this permission notice shall be included in all\n//\t\tcopies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// \t\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n#ifndef DEXPOSED_DLFCN_H\n#define DEXPOSED_DLFCN_H\n\n#include <cstdlib>\n#include <string.h>\n#include <unistd.h>\n\nextern \"C\" {\n\n    void *fake_dlopen(const char *libpath, int flags);\n    void *fake_dlsym(void *handle, const char *name);\n\n};\n#endif //DEXPOSED_DLFCN_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Jni/Helper.h",
    "content": "//\n// VirtualApp Native Project\n//\n\n#ifndef NDK_LOG_H\n#define NDK_LOG_H\n\n#include <fb/include/fb/fbjni.h>\n\n#define NATIVE_METHOD(func_ptr, func_name, signature) { func_name, signature, reinterpret_cast<void*>(func_ptr) }\n\nclass ScopeUtfString {\npublic:\n    ScopeUtfString(jstring j_str) : _j_str(j_str),\n                                    _c_str(facebook::jni::Environment::current()->GetStringUTFChars(j_str, NULL)) {\n    }\n\n    const char *c_str() {\n        return _c_str;\n    }\n\n    ~ScopeUtfString() {\n        facebook::jni::Environment::current()->ReleaseStringUTFChars(_j_str, _c_str);\n    }\n\nprivate:\n    jstring _j_str;\n    const char *_c_str;\n};\n\n#endif //NDK_LOG_H"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Jni/VAJni.cpp",
    "content": "#include <elf.h>//\n// VirtualApp Native Project\n//\n#include <Foundation/IOUniformer.h>\n#include <fb/include/fb/Build.h>\n#include <fb/include/fb/ALog.h>\n#include <fb/include/fb/fbjni.h>\n#include <ctime>\n#include \"VAJni.h\"\n\nusing namespace facebook::jni;\n\nstatic void jni_nativeLaunchEngine(alias_ref<jclass> clazz, JArrayClass<jobject> javaMethods,\n                                   jstring packageName,\n                                   jboolean isArt, jint apiLevel, jint cameraMethodType) {\n    hookAndroidVM(javaMethods, packageName, isArt, apiLevel, cameraMethodType);\n}\n\nstatic void jni_disableJit(alias_ref<jclass> clazz, jint apiLevel) {\n    disableJit(apiLevel);\n}\n\nstatic void jni_nativeEnableIORedirect(alias_ref<jclass>, jstring selfSoPath, jint apiLevel,\n                                       jint preview_api_level) {\n    ScopeUtfString so_path(selfSoPath);\n    IOUniformer::startUniformer(so_path.c_str(), apiLevel, preview_api_level);\n}\n\nstatic void jni_nativeIOWhitelist(alias_ref<jclass> jclazz, jstring _path) {\n    ScopeUtfString path(_path);\n    IOUniformer::whitelist(path.c_str());\n}\n\nstatic void jni_nativeIOForbid(alias_ref<jclass> jclazz, jstring _path) {\n    ScopeUtfString path(_path);\n    IOUniformer::forbid(path.c_str());\n}\n\n\nstatic void jni_nativeIORedirect(alias_ref<jclass> jclazz, jstring origPath, jstring newPath) {\n    ScopeUtfString orig_path(origPath);\n    ScopeUtfString new_path(newPath);\n    IOUniformer::redirect(orig_path.c_str(), new_path.c_str());\n\n}\n\nstatic jstring jni_nativeGetRedirectedPath(alias_ref<jclass> jclazz, jstring origPath) {\n    ScopeUtfString orig_path(origPath);\n    const char *redirected_path = IOUniformer::query(orig_path.c_str());\n    if (redirected_path != NULL) {\n        return Environment::current()->NewStringUTF(redirected_path);\n    }\n    return NULL;\n}\n\nstatic jstring jni_nativeReverseRedirectedPath(alias_ref<jclass> jclazz, jstring redirectedPath) {\n    ScopeUtfString redirected_path(redirectedPath);\n    const char *orig_path = IOUniformer::reverse(redirected_path.c_str());\n    return Environment::current()->NewStringUTF(orig_path);\n}\n\n\nalias_ref<jclass> nativeEngineClass;\n\nconst char hexcode[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',\n                        'F'};\n\nJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {\n    JNIEnv* env;\n    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {\n        return -1;\n    }\n\n    return initialize(vm, [] {\n        nativeEngineClass = findClassStatic(\"com/lody/virtual/client/NativeEngine\");\n        nativeEngineClass->registerNatives({\n                        makeNativeMethod(\"nativeEnableIORedirect\",\n                                         jni_nativeEnableIORedirect),\n                        makeNativeMethod(\"nativeIOWhitelist\",\n                                         jni_nativeIOWhitelist),\n                        makeNativeMethod(\"nativeIOForbid\",\n                                         jni_nativeIOForbid),\n                        makeNativeMethod(\"nativeIORedirect\",\n                                         jni_nativeIORedirect),\n                        makeNativeMethod(\"nativeGetRedirectedPath\",\n                                         jni_nativeGetRedirectedPath),\n                        makeNativeMethod(\"nativeReverseRedirectedPath\",\n                                         jni_nativeReverseRedirectedPath),\n                        makeNativeMethod(\"nativeLaunchEngine\",\n                                         jni_nativeLaunchEngine),\n                        makeNativeMethod(\"disableJit\", jni_disableJit)\n                }\n        );\n    });\n}\n\nextern \"C\" __attribute__((constructor)) void _init(void) {\n    IOUniformer::init_env_before_all();\n}\n\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Jni/VAJni.h",
    "content": "//\n// VirtualApp Native Project\n//\n\n#ifndef NDK_CORE_H\n#define NDK_CORE_H\n\n#include <jni.h>\n#include <stdlib.h>\n\n\n#include \"Helper.h\"\n#include \"Foundation/VMPatch.h\"\n#include \"Foundation/IOUniformer.h\"\n\nextern alias_ref<jclass> nativeEngineClass;\n\nJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);\nJNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);\n\n\n#endif //NDK_CORE_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/Buffer.hpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_BUFFER_HPP\n#define SUBSTRATE_BUFFER_HPP\n\n#include <string.h>\n\ntemplate <typename Type_>\n_disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) {\n    *reinterpret_cast<Type_ *>(buffer) = value;\n    buffer += sizeof(Type_);\n}\n\n_disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) {\n    memcpy(buffer, data, size);\n    buffer += size;\n}\n\n#endif//SUBSTRATE_BUFFER_HPP\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/CydiaSubstrate.h",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_H_\n#define SUBSTRATE_H_\n\n#ifdef __APPLE__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <mach-o/nlist.h>\n#ifdef __cplusplus\n}\n#endif\n\n#include <objc/runtime.h>\n#include <objc/message.h>\n#endif\n\n#include <dlfcn.h>\n#include <stdlib.h>\n\n#define _finline \\\n    inline __attribute__((__always_inline__))\n#define _disused \\\n    __attribute__((__unused__))\n\n#define _extern \\\n    extern \"C\" __attribute__((__visibility__(\"default\")))\n\n#ifdef __cplusplus\n#define _default(value) = value\n#else\n#define _default(value)\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nbool MSHookProcess(pid_t pid, const char *library);\n\ntypedef const void *MSImageRef;\n\nMSImageRef MSGetImageByName(const char *file);\nvoid *MSFindSymbol(MSImageRef image, const char *name);\n\nvoid MSHookFunction(void *symbol, void *replace, void **result);\n\n#ifdef __APPLE__\n#ifdef __arm__\n__attribute__((__deprecated__))\nIMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL));\n#endif\nvoid MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result);\n#endif\n\n#ifdef SubstrateInternal\ntypedef void *SubstrateAllocatorRef;\ntypedef struct __SubstrateProcess *SubstrateProcessRef;\ntypedef struct __SubstrateMemory *SubstrateMemoryRef;\n\nSubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid);\nvoid SubstrateProcessRelease(SubstrateProcessRef process);\n\nSubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size);\nvoid SubstrateMemoryRelease(SubstrateMemoryRef memory);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#ifdef __cplusplus\n\n#ifdef SubstrateInternal\nstruct SubstrateHookMemory {\n    SubstrateMemoryRef handle_;\n\n    SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) :\n        handle_(SubstrateMemoryCreate(NULL, NULL, data, size))\n    {\n    }\n\n    ~SubstrateHookMemory() {\n        if (handle_ != NULL)\n            SubstrateMemoryRelease(handle_);\n    }\n};\n#endif\n\n\ntemplate<typename Type_>\nstatic inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) {\n    MSHookFunction(\n            reinterpret_cast<void *>(symbol),\n            reinterpret_cast<void *>(replace),\n            reinterpret_cast<void **>(result)\n    );\n}\n\ntemplate<typename Type_>\nstatic inline void MSHookFunction(Type_ *symbol, Type_ *replace) {\n    return MSHookFunction(symbol, replace, reinterpret_cast<Type_ **>(NULL));\n}\n\ntemplate<typename Type_>\nstatic inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) {\n    value = reinterpret_cast<Type_ *>(MSFindSymbol(image, name));\n}\n\ntemplate<typename Type_>\nstatic inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) {\n    Type_ *symbol;\n    MSHookSymbol(symbol, name);\n    return MSHookFunction(symbol, replace, result);\n}\n\n#endif\n\n#define MSHook(type, name, args...) \\\n    _disused static type (*_ ## name)(args); \\\n    static type $ ## name(args)\n\n#ifdef __cplusplus\n#define MSHake(name) \\\n    &$ ## name, &_ ## name\n#else\n#define MSHake(name) \\\n    &$ ## name, (void **) &_ ## name\n#endif\n\n\n#endif//SUBSTRATE_H_\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateARM.hpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_ARM_HPP\n#define SUBSTRATE_ARM_HPP\n\nenum A$r {\n    A$r0, A$r1, A$r2, A$r3,\n    A$r4, A$r5, A$r6, A$r7,\n    A$r8, A$r9, A$r10, A$r11,\n    A$r12, A$r13, A$r14, A$r15,\n    A$sp = A$r13,\n    A$lr = A$r14,\n    A$pc = A$r15\n};\n\nenum A$c {\n    A$eq, A$ne, A$cs, A$cc,\n    A$mi, A$pl, A$vs, A$vc,\n    A$hi, A$ls, A$ge, A$lt,\n    A$gt, A$le, A$al,\n    A$hs = A$cs,\n    A$lo = A$cc\n};\n\n#define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \\\n    (0xe10f0000 | ((rd) << 12))\n#define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \\\n    (0xe128f000 | (rm))\n#define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \\\n    (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im))\n#define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \\\n    (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im))\n#define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \\\n    (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff))\n#define A$blx_rm(rm) /* blx rm */ \\\n    (0xe12fff30 | (rm))\n#define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \\\n    (0xe1a00000 | ((rd) << 12) | (rm))\n#define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \\\n    (0xe8b00000 | (A$sp << 16) | (rs))\n#define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \\\n    (0xe9200000 | (A$sp << 16) | (rs))\n#define A$stmia_sp$_$r0$  0xe8ad0001 /* stmia sp!, {r0}   */\n#define A$bx_r0           0xe12fff10 /* bx r0             */\n\n#endif//SUBSTRATE_ARM_HPP\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.cpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#include \"SubstrateHook.h\"\n#include \"SubstrateDebug.hpp\"\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n_extern bool MSDebug;\nbool MSDebug = false;\n\nstatic char _MSHexChar(uint8_t value) {\n    return value < 0x20 || value >= 0x80 ? '.' : value;\n}\n\n#define HexWidth_ 16\n#define HexDepth_ 4\n\nvoid MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) {\n    const uint8_t *data((const uint8_t *) vdata);\n\n    size_t i(0), j;\n\n    char d[256];\n    size_t b(0);\n    d[0] = '\\0';\n\n    while (i != size) {\n        if (i % HexWidth_ == 0) {\n            if (mark != NULL)\n                b += sprintf(d + b, \"\\n[%s] \", mark);\n            b += sprintf(d + b, \"0x%.3zx:\", i);\n        }\n\n        b += sprintf(d + b, \" \");\n\n        for (size_t q(0); q != stride; ++q)\n            b += sprintf(d + b, \"%.2x\", data[i + stride - q - 1]);\n\n        i += stride;\n\n        for (size_t q(1); q != stride; ++q)\n            b += sprintf(d + b, \" \");\n\n        if (i % HexDepth_ == 0)\n            b += sprintf(d + b, \" \");\n\n        if (i % HexWidth_ == 0) {\n            b += sprintf(d + b, \" \");\n            for (j = i - HexWidth_; j != i; ++j)\n                b += sprintf(d + b, \"%c\", _MSHexChar(data[j]));\n\n            lprintf(\"%s\", d);\n            b = 0;\n            d[0] = '\\0';\n        }\n    }\n\n    if (i % HexWidth_ != 0) {\n        for (j = i % HexWidth_; j != HexWidth_; ++j)\n            b += sprintf(d + b, \"   \");\n        for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j)\n            b += sprintf(d + b, \" \");\n        b += sprintf(d + b, \" \");\n        for (j = i / HexWidth_ * HexWidth_; j != i; ++j)\n            b += sprintf(d + b, \"%c\", _MSHexChar(data[j]));\n\n        lprintf(\"%s\", d);\n        b = 0;\n        d[0] = '\\0';\n    }\n}\n\nvoid MSLogHex(const void *vdata, size_t size, const char *mark) {\n    return MSLogHexEx(vdata, size, 1, mark);\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateDebug.hpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_DEBUG_HPP\n#define SUBSTRATE_DEBUG_HPP\n\n#include \"SubstrateLog.hpp\"\n#define lprintf(format, ...) \\\n    MSLog(MSLogLevelNotice, format, ## __VA_ARGS__)\n\nextern \"C\" bool MSDebug;\nvoid MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0);\nvoid MSLogHex(const void *vdata, size_t size, const char *mark = 0);\n\n#endif//SUBSTRATE_DEBUG_HPP\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.cpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#define SubstrateInternal\n#include \"CydiaSubstrate.h\"\n\n#include <sys/mman.h>\n\n#define _trace() do { \\\n    MSLog(MSLogLevelNotice, \"_trace(%u)\", __LINE__); \\\n} while (false)\n\n#if defined(__i386__) || defined(__x86_64__)\n#include \"hde64.h\"\n#endif\n\n#include \"SubstrateDebug.hpp\"\n\n#include <errno.h>\n#include <stdio.h>\n#include <string.h>\n\n#ifdef __arm__\n/* WebCore (ARM) PC-Relative:\nX    1  ldr r*,[pc,r*] !=\n     2 fldd d*,[pc,#*]\nX    5  str r*,[pc,r*] !=\n     8 flds s*,[pc,#*]\n   400  ldr r*,[pc,r*] ==\n   515  add r*, pc,r*  ==\nX 4790  ldr r*,[pc,#*]    */\n\n// x=0; while IFS= read -r line; do if [[ ${#line} -ne 0 && $line == +([^\\;]): ]]; then x=2; elif [[ $line == ' +'* && $x -ne 0 ]]; then ((--x)); echo \"$x${line}\"; fi; done <WebCore.asm >WebCore.pc\n// grep pc WebCore.pc | cut -c 40- | sed -Ee 's/^ldr *(ip|r[0-9]*),\\[pc,\\#0x[0-9a-f]*\\].*/ ldr r*,[pc,#*]/;s/^add *r[0-9]*,pc,r[0-9]*.*/ add r*, pc,r*/;s/^(st|ld)r *r([0-9]*),\\[pc,r([0-9]*)\\].*/ \\1r r\\2,[pc,r\\3]/;s/^fld(s|d) *(s|d)[0-9]*,\\[pc,#0x[0-9a-f]*].*/fld\\1 \\2*,[pc,#*]/' | sort | uniq -c | sort -n\n\n#include \"SubstrateARM.hpp\"\n\n#define T$Label(l, r) \\\n    (((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2))\n\n#define T$pop_$r0$ 0xbc01 // pop {r0}\n#define T$b(im) /* b im */ \\\n    (0xde00 | (im & 0xff))\n#define T$blx(rm) /* blx rm */ \\\n    (0x4780 | (rm << 3))\n#define T$bx(rm) /* bx rm */ \\\n    (0x4700 | (rm << 3))\n#define T$nop /* nop */ \\\n    (0x46c0)\n\n#define T$add_rd_rm(rd, rm) /* add rd, rm */ \\\n    (0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7))\n#define T$push_r(r) /* push r... */ \\\n    (0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff))\n#define T$pop_r(r) /* pop r... */ \\\n    (0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff))\n#define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \\\n    (0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7))\n#define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \\\n    (0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd))\n#define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \\\n    (0x4800 | ((rd) << 8) | ((im) & 0xff))\n#define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \\\n    (0x2000 | ((rn) << 8) | ((im) & 0xff))\n#define T$it$_cd(cd, ms) /* it<ms>, cd */ \\\n    (0xbf00 | ((cd) << 4) | (ms))\n#define T$cbz$_rn_$im(op,rn,im) /* cb<op>z rn, #im */ \\\n    (0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn))\n#define T$b$_$im(cond,im) /* b<cond> #im */ \\\n    (cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff))\n\n#define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \\\n    (0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn))\n#define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \\\n    (((rt) << 12) | abs(im))\n\n#define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \\\n    (0xf3ef)\n#define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \\\n    (0x8000 | ((rd) << 8))\n\n#define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \\\n    (0xf380 | (rn))\n#define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \\\n    (0x8c00)\n#define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \\\n    (T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn))\n\nstatic inline bool A$pcrel$r(uint32_t ic) {\n    return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && (ic & 0x000f0000) == 0x000f0000;\n}\n\nstatic inline bool T$32bit$i(uint16_t ic) {\n    return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000);\n}\n\nstatic inline bool T$pcrel$cbz(uint16_t ic) {\n    return (ic & 0xf500) == 0xb100;\n}\n\nstatic inline bool T$pcrel$b(uint16_t ic) {\n    return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00;\n}\n\nstatic inline bool T2$pcrel$b(uint16_t *ic) {\n    return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0x9000 || (ic[1] & 0xd000) == 0x8000 && (ic[0] & 0x0380) != 0x0380);\n}\n\nstatic inline bool T$pcrel$bl(uint16_t *ic) {\n    return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000);\n}\n\nstatic inline bool T$pcrel$ldr(uint16_t ic) {\n    return (ic & 0xf800) == 0x4800;\n}\n\nstatic inline bool T$pcrel$add(uint16_t ic) {\n    return (ic & 0xff78) == 0x4478;\n}\n\nstatic inline bool T$pcrel$ldrw(uint16_t ic) {\n    return (ic & 0xff7f) == 0xf85f;\n}\n\nstatic size_t MSGetInstructionWidthThumb(void *start) {\n    uint16_t *thumb(reinterpret_cast<uint16_t *>(start));\n    return T$32bit$i(thumb[0]) ? 4 : 2;\n}\n\nstatic size_t MSGetInstructionWidthARM(void *start) {\n    return 4;\n}\n\nextern \"C\" size_t MSGetInstructionWidth(void *start) {\n    if ((reinterpret_cast<uintptr_t>(start) & 0x1) == 0)\n        return MSGetInstructionWidthARM(start);\n    else\n        return MSGetInstructionWidthThumb(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(start) & ~0x1));\n}\n\nstatic size_t SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, void **result) {\n    if (symbol == NULL)\n        return 0;\nprintf(\"SubstrateHookFunctionThumb\\n\");\n    uint16_t *area(reinterpret_cast<uint16_t *>(symbol));\n\n    unsigned align((reinterpret_cast<uintptr_t>(area) & 0x2) == 0 ? 0 : 1);\n    uint16_t *thumb(area + align);\n\n    uint32_t *arm(reinterpret_cast<uint32_t *>(thumb + 2));\n    uint16_t *trail(reinterpret_cast<uint16_t *>(arm + 2));\n\n    if (\n        (align == 0 || area[0] == T$nop) &&\n        thumb[0] == T$bx(A$pc) &&\n        thumb[1] == T$nop &&\n        arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)\n    ) {\n        if (result != NULL)\n            *result = reinterpret_cast<void *>(arm[1]);\n\n        SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1);\n\n        arm[1] = reinterpret_cast<uint32_t>(replace);\n\n        return sizeof(arm[0]);\n    }\n\n    size_t required((trail - area) * sizeof(uint16_t));\n\n    size_t used(0);\n    while (used < required)\n        used += MSGetInstructionWidthThumb(reinterpret_cast<uint8_t *>(area) + used);\n    used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t);\n\n    size_t blank((used - required) / sizeof(uint16_t));\n\n    uint16_t backup[used / sizeof(uint16_t)];\n    memcpy(backup, area, used);\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHexEx(area, used + sizeof(uint16_t), 2, name);\n    }\n\n    if (result != NULL) {\n\n    size_t length(used);\n    for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset)\n        if (T$pcrel$ldr(backup[offset]))\n            length += 3 * sizeof(uint16_t);\n        else if (T$pcrel$b(backup[offset]))\n            length += 6 * sizeof(uint16_t);\n        else if (T2$pcrel$b(backup + offset)) {\n            length += 5 * sizeof(uint16_t);\n            ++offset;\n        } else if (T$pcrel$bl(backup + offset)) {\n            length += 5 * sizeof(uint16_t);\n            ++offset;\n        } else if (T$pcrel$cbz(backup[offset])) {\n            length += 16 * sizeof(uint16_t);\n        } else if (T$pcrel$ldrw(backup[offset])) {\n            length += 4 * sizeof(uint16_t);\n            ++offset;\n        } else if (T$pcrel$add(backup[offset]))\n            length += 6 * sizeof(uint16_t);\n        else if (T$32bit$i(backup[offset]))\n            ++offset;\n\n    unsigned pad((length & 0x2) == 0 ? 0 : 1);\n    length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t);\n\n    uint16_t *buffer(reinterpret_cast<uint16_t *>(mmap(\n        NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0\n    )));\n\n    if (buffer == MAP_FAILED) {\n        MSLog(MSLogLevelError, \"MS:Error:mmap() = %d\", errno);\n        *result = NULL;\n        return 0;\n    }\n\n    if (false) fail: {\n        munmap(buffer, length);\n        *result = NULL;\n        return 0;\n    }\n\n    size_t start(pad), end(length / sizeof(uint16_t));\n    uint32_t *trailer(reinterpret_cast<uint32_t *>(buffer + end));\n    for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) {\n        if (T$pcrel$ldr(backup[offset])) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t immediate : 8;\n                    uint16_t rd : 3;\n                    uint16_t : 5;\n                };\n            } bits = {backup[offset+0]};\n\n            buffer[start+0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+0, end-2) / 4);\n            buffer[start+1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0);\n\n            // XXX: this code \"works\", but is \"wrong\": the mechanism is more complex than this\n            *--trailer = ((reinterpret_cast<uint32_t>(area + offset) + 4) & ~0x2) + bits.immediate * 4;\n\n            start += 2;\n            end -= 2;\n        } else if (T$pcrel$b(backup[offset])) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t imm8 : 8;\n                    uint16_t cond : 4;\n                    uint16_t /*1101*/ : 4;\n                };\n            } bits = {backup[offset+0]};\n\n            intptr_t jump(bits.imm8 << 1);\n            jump |= 1;\n            jump <<= 23;\n            jump >>= 23;\n\n            buffer[start+0] = T$b$_$im(bits.cond, (end-6 - (start+0)) * 2 - 4);\n\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump;\n            *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n            *--trailer = T$nop << 16 | T$bx(A$pc);\n\n            start += 1;\n            end -= 6;\n        } else if (T2$pcrel$b(backup + offset)) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t imm6 : 6;\n                    uint16_t cond : 4;\n                    uint16_t s : 1;\n                    uint16_t : 5;\n                };\n            } bits = {backup[offset+0]};\n\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t imm11 : 11;\n                    uint16_t j2 : 1;\n                    uint16_t a : 1;\n                    uint16_t j1 : 1;\n                    uint16_t : 2;\n                };\n            } exts = {backup[offset+1]};\n\n            intptr_t jump(1);\n            jump |= exts.imm11 << 1;\n            jump |= bits.imm6 << 12;\n\n            if (exts.a) {\n                jump |= bits.s << 24;\n                jump |= (~(bits.s ^ exts.j1) & 0x1) << 23;\n                jump |= (~(bits.s ^ exts.j2) & 0x1) << 22;\n                jump |= bits.cond << 18;\n                jump <<= 7;\n                jump >>= 7;\n            } else {\n                jump |= bits.s << 20;\n                jump |= exts.j2 << 19;\n                jump |= exts.j1 << 18;\n                jump <<= 11;\n                jump >>= 11;\n            }\n\n            buffer[start+0] = T$b$_$im(exts.a ? A$al : bits.cond, (end-6 - (start+0)) * 2 - 4);\n\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump;\n            *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n            *--trailer = T$nop << 16 | T$bx(A$pc);\n\n            ++offset;\n            start += 1;\n            end -= 6;\n        } else if (T$pcrel$bl(backup + offset)) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t immediate : 10;\n                    uint16_t s : 1;\n                    uint16_t : 5;\n                };\n            } bits = {backup[offset+0]};\n\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t immediate : 11;\n                    uint16_t j2 : 1;\n                    uint16_t x : 1;\n                    uint16_t j1 : 1;\n                    uint16_t : 2;\n                };\n            } exts = {backup[offset+1]};\n\n            int32_t jump(0);\n            jump |= bits.s << 24;\n            jump |= (~(bits.s ^ exts.j1) & 0x1) << 23;\n            jump |= (~(bits.s ^ exts.j2) & 0x1) << 22;\n            jump |= bits.immediate << 12;\n            jump |= exts.immediate << 1;\n            jump |= exts.x;\n            jump <<= 7;\n            jump >>= 7;\n\n            buffer[start+0] = T$push_r(1 << A$r7);\n            buffer[start+1] = T$ldr_rd_$pc_im_4$(A$r7, ((end-2 - (start+1)) * 2 - 4 + 2) / 4);\n            buffer[start+2] = T$mov_rd_rm(A$lr, A$r7);\n            buffer[start+3] = T$pop_r(1 << A$r7);\n            buffer[start+4] = T$blx(A$lr);\n\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump;\n\n            ++offset;\n            start += 5;\n            end -= 2;\n        } else if (T$pcrel$cbz(backup[offset])) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t rn : 3;\n                    uint16_t immediate : 5;\n                    uint16_t : 1;\n                    uint16_t i : 1;\n                    uint16_t : 1;\n                    uint16_t op : 1;\n                    uint16_t : 4;\n                };\n            } bits = {backup[offset+0]};\n\n            intptr_t jump(1);\n            jump |= bits.i << 6;\n            jump |= bits.immediate << 1;\n\n            //jump <<= 24;\n            //jump >>= 24;\n\n            unsigned rn(bits.rn);\n            unsigned rt(rn == A$r7 ? A$r6 : A$r7);\n\n            buffer[start+0] = T$push_r(1 << rt);\n            buffer[start+1] = T1$mrs_rd_apsr(rt);\n            buffer[start+2] = T2$mrs_rd_apsr(rt);\n            buffer[start+3] = T$cbz$_rn_$im(bits.op, rn, (end-10 - (start+3)) * 2 - 4);\n            buffer[start+4] = T1$msr_apsr_nzcvqg_rn(rt);\n            buffer[start+5] = T2$msr_apsr_nzcvqg_rn(rt);\n            buffer[start+6] = T$pop_r(1 << rt);\n\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump;\n            *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n            *--trailer = T$nop << 16 | T$bx(A$pc);\n            *--trailer = T$nop << 16 | T$pop_r(1 << rt);\n            *--trailer = T$msr_apsr_nzcvqg_rn(rt);\n\n#if 0\n            if ((start & 0x1) == 0)\n                buffer[start++] = T$nop;\n            buffer[start++] = T$bx(A$pc);\n            buffer[start++] = T$nop;\n\n            uint32_t *arm(reinterpret_cast<uint32_t *>(buffer + start));\n            arm[0] = A$add(A$lr, A$pc, 1);\n            arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8);\n#endif\n\n            start += 7;\n            end -= 10;\n        } else if (T$pcrel$ldrw(backup[offset])) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t : 7;\n                    uint16_t u : 1;\n                    uint16_t : 8;\n                };\n            } bits = {backup[offset+0]};\n\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t immediate : 12;\n                    uint16_t rt : 4;\n                };\n            } exts = {backup[offset+1]};\n\n            buffer[start+0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2));\n            buffer[start+1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, (int)T$Label(start+0, end-2));\n\n            buffer[start+2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0);\n            buffer[start+3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0);\n\n            // XXX: this code \"works\", but is \"wrong\": the mechanism is more complex than this\n            *--trailer = ((reinterpret_cast<uint32_t>(area + offset) + 4) & ~0x2) + (bits.u == 0 ? -exts.immediate : exts.immediate);\n\n            ++offset;\n            start += 4;\n            end -= 2;\n        } else if (T$pcrel$add(backup[offset])) {\n            union {\n                uint16_t value;\n\n                struct {\n                    uint16_t rd : 3;\n                    uint16_t rm : 3;\n                    uint16_t h2 : 1;\n                    uint16_t h1 : 1;\n                    uint16_t : 8;\n                };\n            } bits = {backup[offset+0]};\n\n            if (bits.h1) {\n                MSLog(MSLogLevelError, \"MS:Error:pcrel(%u):add (rd > r7)\", offset);\n                goto fail;\n            }\n\n            unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7);\n\n            buffer[start+0] = T$push_r(1 << rt);\n            buffer[start+1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd);\n            buffer[start+2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+2, end-2) / 4);\n            buffer[start+3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt);\n            buffer[start+4] = T$pop_r(1 << rt);\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4;\n\n            start += 5;\n            end -= 2;\n        } else if (T$32bit$i(backup[offset])) {\n            buffer[start++] = backup[offset];\n            buffer[start++] = backup[++offset];\n        } else {\n            buffer[start++] = backup[offset];\n        }\n    }\n\n    buffer[start++] = T$bx(A$pc);\n    buffer[start++] = T$nop;\n\n    uint32_t *transfer = reinterpret_cast<uint32_t *>(buffer + start);\n    transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n    transfer[1] = reinterpret_cast<uint32_t>(area + used / sizeof(uint16_t)) + 1;\n\n    if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) {\n        MSLog(MSLogLevelError, \"MS:Error:mprotect():%d\", errno);\n        return 0;\n    }\n\n    *result = reinterpret_cast<uint8_t *>(buffer + pad) + 1;\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", *result);\n        MSLogHexEx(buffer, length, 2, name);\n    }\n\n    }\n\n    {\n        SubstrateHookMemory code(process, area, used);\n\n        if (align != 0)\n            area[0] = T$nop;\n\n        thumb[0] = T$bx(A$pc);\n        thumb[1] = T$nop;\n\n        arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n        arm[1] = reinterpret_cast<uint32_t>(replace);\n\n        for (unsigned offset(0); offset != blank; ++offset)\n            trail[offset] = T$nop;\n    }\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHexEx(area, used + sizeof(uint16_t), 2, name);\n    }\n\t\n\treturn used;\n}\n\nstatic size_t SubstrateHookFunctionARM(SubstrateProcessRef process, void *symbol, void *replace, void **result) {\n    if (symbol == NULL)\n        return 0;\nprintf(\"SubstrateHookFunctionARM\\n\");\n    uint32_t *area(reinterpret_cast<uint32_t *>(symbol));\n    uint32_t *arm(area);\n\n    const size_t used(8);\n\n    uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]};\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHexEx(area, used + sizeof(uint32_t), 4, name);\n    }\n\n    if (result != NULL) {\n\n    if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) {\n        *result = reinterpret_cast<void *>(backup[1]);\n        \n\t\treturn sizeof(backup[0]);\n    }\n\n    size_t length(used);\n    for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset)\n        if (A$pcrel$r(backup[offset])) {\n            if ((backup[offset] & 0x02000000) == 0 || (backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f))\n                length += 2 * sizeof(uint32_t);\n            else\n                length += 4 * sizeof(uint32_t);\n        }\n\n    length += 2 * sizeof(uint32_t);\n\n    uint32_t *buffer(reinterpret_cast<uint32_t *>(mmap(\n        NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0\n    )));\n\n    if (buffer == MAP_FAILED) {\n        MSLog(MSLogLevelError, \"MS:Error:mmap() = %d\", errno);\n        *result = NULL;\n        return 0;\n    }\n\n    if (false) fail: {\n        munmap(buffer, length);\n        *result = NULL;\n        return 0;\n    }\n\n    size_t start(0), end(length / sizeof(uint32_t));\n    uint32_t *trailer(reinterpret_cast<uint32_t *>(buffer + end));\n    for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset)\n        if (A$pcrel$r(backup[offset])) {\n            union {\n                uint32_t value;\n\n                struct {\n                    uint32_t rm : 4;\n                    uint32_t : 1;\n                    uint32_t shift : 2;\n                    uint32_t shiftamount : 5;\n                    uint32_t rd : 4;\n                    uint32_t rn : 4;\n                    uint32_t l : 1;\n                    uint32_t w : 1;\n                    uint32_t b : 1;\n                    uint32_t u : 1;\n                    uint32_t p : 1;\n                    uint32_t mode : 1;\n                    uint32_t type : 2;\n                    uint32_t cond : 4;\n                };\n            } bits = {backup[offset+0]}, copy(bits);\n\n            bool guard;\n            if (bits.mode == 0 || bits.rd != bits.rm) {\n                copy.rn = bits.rd;\n                guard = false;\n            } else {\n                copy.rn = bits.rm != A$r0 ? A$r0 : A$r1;\n                guard = true;\n            }\n\n            if (guard)\n                buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn));\n\n            buffer[start+0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, (int)(end-1 - (start+0)) * 4 - 8);\n            buffer[start+1] = copy.value;\n\n            start += 2;\n\n            if (guard)\n                buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn));\n\n            *--trailer = reinterpret_cast<uint32_t>(area + offset) + 8;\n            end -= 1;\n        } else\n            buffer[start++] = backup[offset];\n\n    buffer[start+0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n    buffer[start+1] = reinterpret_cast<uint32_t>(area + used / sizeof(uint32_t));\n\n    if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) {\n        MSLog(MSLogLevelError, \"MS:Error:mprotect():%d\", errno);\n        goto fail;\n    }\n\n    *result = buffer;\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", *result);\n        MSLogHexEx(buffer, length, 4, name);\n    }\n\n    }\n\n    {\n        SubstrateHookMemory code(process, symbol, used);\n\n        arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8);\n        arm[1] = reinterpret_cast<uint32_t>(replace);\n    }\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHexEx(area, used + sizeof(uint32_t), 4, name);\n    }\n\t\n\treturn used;\n}\n\nstatic size_t SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) {\n    if (MSDebug)\n        MSLog(MSLogLevelNotice, \"SubstrateHookFunction(%p, %p, %p, %p)\\n\", process, symbol, replace, result);\n    if ((reinterpret_cast<uintptr_t>(symbol) & 0x1) == 0)\n        return SubstrateHookFunctionARM(process, symbol, replace, result);\n    else\n        return SubstrateHookFunctionThumb(process, reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(symbol) & ~0x1), replace, result);\n}\n#endif\n\n#if defined(__i386__) || defined(__x86_64__)\n\n#include \"SubstrateX86.hpp\"\n\nstatic size_t MSGetInstructionWidthIntel(void *start) {\n    hde64s decode;\n    return hde64_disasm(start, &decode);\n}\n\nstatic void SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) {\n    if (MSDebug)\n        MSLog(MSLogLevelNotice, \"MSHookFunction(%p, %p, %p)\\n\", symbol, replace, result);\n    if (symbol == NULL)\n        return;\n\n    uintptr_t source(reinterpret_cast<uintptr_t>(symbol));\n    uintptr_t target(reinterpret_cast<uintptr_t>(replace));\n\n    uint8_t *area(reinterpret_cast<uint8_t *>(symbol));\n\n    size_t required(MSSizeOfJump(target, source));\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHex(area, 32, name);\n    }\n\n    size_t used(0);\n    while (used < required) {\n        size_t width(MSGetInstructionWidthIntel(area + used));\n        if (width == 0) {\n            MSLog(MSLogLevelError, \"MS:Error:MSGetInstructionWidthIntel(%p) == 0\", area + used);\n            return;\n        }\n\n        used += width;\n    }\n\n    size_t blank(used - required);\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHex(area, used + sizeof(uint16_t), name);\n    }\n\n    uint8_t backup[used];\n    memcpy(backup, area, used);\n\n    if (result != NULL) {\n\n    if (backup[0] == 0xe9) {\n        *result = reinterpret_cast<void *>(source + 5 + *reinterpret_cast<uint32_t *>(backup + 1));\n        return;\n    }\n\n    if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) {\n        *result = *reinterpret_cast<void **>(source + 6 + *reinterpret_cast<uint32_t *>(backup + 2));\n        return;\n    }\n\n    size_t length(used + MSSizeOfJump(source + used));\n\n    for (size_t offset(0), width; offset != used; offset += width) {\n        hde64s decode;\n        hde64_disasm(backup + offset, &decode);\n        width = decode.len;\n        //_assert(width != 0 && offset + width <= used);\n\n#ifdef __LP64__\n        if ((decode.modrm & 0xc7) == 0x05) {\n            if (decode.opcode == 0x8b) {\n                void *destiny(area + offset + width + int32_t(decode.disp.disp32));\n                uint8_t reg(decode.rex_r << 3 | decode.modrm_reg);\n                length -= decode.len;\n                length += MSSizeOfPushPointer(destiny);\n                length += MSSizeOfPop(reg);\n                length += MSSizeOfMove64();\n            } else {\n                MSLog(MSLogLevelError, \"MS:Error: Unknown RIP-Relative (%.2x %.2x)\", decode.opcode, decode.opcode2);\n                continue;\n            }\n        } else\n#endif\n\n        if (backup[offset] == 0xe8) {\n            int32_t relative(*reinterpret_cast<int32_t *>(backup + offset + 1));\n            void *destiny(area + offset + decode.len + relative);\n\n            if (relative == 0) {\n                length -= decode.len;\n                length += MSSizeOfPushPointer(destiny);\n            } else {\n                length += MSSizeOfSkip();\n                length += MSSizeOfJump(destiny);\n            }\n        } else if (backup[offset] == 0xeb) {\n            length -= decode.len;\n            length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1));\n        } else if (backup[offset] == 0xe9) {\n            length -= decode.len;\n            length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int32_t *>(backup + offset + 1));\n        } else if (\n            backup[offset] == 0xe3 ||\n            (backup[offset] & 0xf0) == 0x70\n            // XXX: opcode2 & 0xf0 is 0x80?\n        ) {\n            length += decode.len;\n            length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1));\n        }\n    }\n\n    uint8_t *buffer(reinterpret_cast<uint8_t *>(mmap(\n        NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0\n    )));\n\n    if (buffer == MAP_FAILED) {\n        MSLog(MSLogLevelError, \"MS:Error:mmap() = %d\", errno);\n        *result = NULL;\n        return;\n    }\n\n    if (false) fail: {\n        munmap(buffer, length);\n        *result = NULL;\n        return;\n    }\n\n    {\n        uint8_t *current(buffer);\n\n        for (size_t offset(0), width; offset != used; offset += width) {\n            hde64s decode;\n            hde64_disasm(backup + offset, &decode);\n            width = decode.len;\n            //_assert(width != 0 && offset + width <= used);\n\n#ifdef __LP64__\n            if ((decode.modrm & 0xc7) == 0x05) {\n                if (decode.opcode == 0x8b) {\n                    void *destiny(area + offset + width + int32_t(decode.disp.disp32));\n                    uint8_t reg(decode.rex_r << 3 | decode.modrm_reg);\n                    MSPushPointer(current, destiny);\n                    MSWritePop(current, reg);\n                    MSWriteMove64(current, reg, reg);\n                } else {\n                    MSLog(MSLogLevelError, \"MS:Error: Unknown RIP-Relative (%.2x %.2x)\", decode.opcode, decode.opcode2);\n                    goto copy;\n                }\n            } else\n#endif\n\n            if (backup[offset] == 0xe8) {\n                int32_t relative(*reinterpret_cast<int32_t *>(backup + offset + 1));\n                if (relative == 0)\n                    MSPushPointer(current, area + offset + decode.len);\n                else {\n                    MSWrite<uint8_t>(current, 0xe8);\n                    MSWrite<int32_t>(current, MSSizeOfSkip());\n                    void *destiny(area + offset + decode.len + relative);\n                    MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip()));\n                    MSWriteJump(current, destiny);\n                }\n            } else if (backup[offset] == 0xeb)\n                MSWriteJump(current, area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1));\n            else if (backup[offset] == 0xe9)\n                MSWriteJump(current, area + offset + decode.len + *reinterpret_cast<int32_t *>(backup + offset + 1));\n            else if (\n                backup[offset] == 0xe3 ||\n                (backup[offset] & 0xf0) == 0x70\n            ) {\n                MSWrite<uint8_t>(current, backup[offset]);\n                MSWrite<uint8_t>(current, 2);\n                MSWrite<uint8_t>(current, 0xeb);\n                void *destiny(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1));\n                MSWrite<uint8_t>(current, MSSizeOfJump(destiny, current + 1));\n                MSWriteJump(current, destiny);\n            } else\n#ifdef __LP64__\n                copy:\n#endif\n            {\n                MSWrite(current, backup + offset, width);\n            }\n        }\n\n        MSWriteJump(current, area + used);\n    }\n\n    if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) {\n        MSLog(MSLogLevelError, \"MS:Error:mprotect():%d\", errno);\n        goto fail;\n    }\n\n    *result = buffer;\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", *result);\n        MSLogHex(buffer, length, name);\n    }\n\n    }\n\n    {\n        SubstrateHookMemory code(process, area, used);\n\n        uint8_t *current(area);\n        MSWriteJump(current, target);\n        for (unsigned offset(0); offset != blank; ++offset)\n            MSWrite<uint8_t>(current, 0x90);\n    }\n\n    if (MSDebug) {\n        char name[16];\n        sprintf(name, \"%p\", area);\n        MSLogHex(area, used + sizeof(uint16_t), name);\n    }\n}\n#endif\n\n_extern void MSHookFunction(void *symbol, void *replace, void **result) {\n#ifndef __aarch64__\n     SubstrateHookFunction(NULL, symbol, replace, result);\n#endif\n}\n\n#if defined(__APPLE__) && defined(__arm__)\n_extern void _Z14MSHookFunctionPvS_PS_(void *symbol, void *replace, void **result) {\n    return MSHookFunction(symbol, replace, result);\n}\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateHook.h",
    "content": "#ifndef __SUBSTRATEHOOK_H__\n#define __SUBSTRATEHOOK_H__\n\n\n#include <stdlib.h>\n\n#define _extern extern \"C\" __attribute__((__visibility__(\"default\")))\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid MSHookFunction(void *symbol, void *replace, void **result);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateLog.hpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_LOG_HPP\n#define SUBSTRATE_LOG_HPP\n\n#if 0\n#include <android/log.h>\n\n#define MSLog(level, format, ...) ((void)__android_log_print(level, \"NNNN\", format, __VA_ARGS__))\n\n#define MSLogLevelNotice ANDROID_LOG_INFO\n#define MSLogLevelWarning ANDROID_LOG_WARN\n#define MSLogLevelError ANDROID_LOG_ERROR\n\n#else\n\n#define MSLog(level, format, ...) printf(format, __VA_ARGS__)\n\n#endif\n\n#endif//SUBSTRATE_LOG_HPP\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstratePosixMemory.cpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#define SubstrateInternal\n#include \"CydiaSubstrate.h\"\n#include \"SubstrateLog.hpp\"\n\n#include <sys/mman.h>\n\n#include <errno.h>\n#include <stdio.h>\n#include <unistd.h>\n\nextern \"C\" void __clear_cache (void *beg, void *end);\n\nstruct __SubstrateMemory {\n    void *address_;\n    size_t width_;\n\n    __SubstrateMemory(void *address, size_t width) :\n        address_(address),\n        width_(width)\n    {\n    }\n};\n\nextern \"C\" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) {\n    if (allocator != NULL) {\n        MSLog(MSLogLevelError, \"MS:Error:allocator != %d\", 0);\n        return NULL;\n    }\n\n    if (size == 0)\n        return NULL;\n\n    long page(sysconf(_SC_PAGESIZE)); // Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize\n\n    uintptr_t base(reinterpret_cast<uintptr_t>(data) / page * page);\n    size_t width(((reinterpret_cast<uintptr_t>(data) + size - 1) / page + 1) * page - base);\n    void *address(reinterpret_cast<void *>(base));\n\n    if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {\n        MSLog(MSLogLevelError, \"MS:Error:mprotect() = %d\", errno);\n        return NULL;\n    }\n\n    return new __SubstrateMemory(address, width);\n}\n\nextern \"C\" void SubstrateMemoryRelease(SubstrateMemoryRef memory) {\n    if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)\n        MSLog(MSLogLevelError, \"MS:Error:mprotect() = %d\", errno);\n\n    __clear_cache(reinterpret_cast<char *>(memory->address_), reinterpret_cast<char *>(memory->address_) + memory->width_);\n\n    delete memory;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/SubstrateX86.hpp",
    "content": "/* Cydia Substrate - Powerful Code Insertion Platform\n * Copyright (C) 2008-2011  Jay Freeman (saurik)\n*/\n\n/* GNU Lesser General Public License, Version 3 {{{ */\n/*\n * Substrate is free software: you can redistribute it and/or modify it under\n * the terms of the GNU Lesser General Public License as published by the\n * Free Software Foundation, either version 3 of the License, or (at your\n * option) any later version.\n *\n * Substrate is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public\n * License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License\n * along with Substrate.  If not, see <http://www.gnu.org/licenses/>.\n**/\n/* }}} */\n\n#ifndef SUBSTRATE_X86_HPP\n#define SUBSTRATE_X86_HPP\n\n#include \"Buffer.hpp\"\n\n#ifdef __LP64__\nstatic const bool ia32 = false;\n#else\nstatic const bool ia32 = true;\n#endif\n\nenum I$r {\n    I$rax, I$rcx, I$rdx, I$rbx,\n    I$rsp, I$rbp, I$rsi, I$rdi,\n    I$r8, I$r9, I$r10, I$r11,\n    I$r12, I$r13, I$r14, I$r15,\n};\n\n_disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) {\n    intptr_t offset(target - source);\n    return int32_t(offset) == offset;\n}\n\n_disused static size_t MSSizeOfSkip() {\n    return 5;\n}\n\n_disused static size_t MSSizeOfPushPointer(uintptr_t target) {\n    return uint64_t(target) >> 32 == 0 ? 5 : 13;\n}\n\n_disused static size_t MSSizeOfPushPointer(void *target) {\n    return MSSizeOfPushPointer(reinterpret_cast<uintptr_t>(target));\n}\n\n_disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) {\n    if (ia32 || !blind && MSIs32BitOffset(target, source + 5))\n        return MSSizeOfSkip();\n    else\n        return MSSizeOfPushPointer(target) + 1;\n}\n\n_disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) {\n    return MSSizeOfJump(false, target, source);\n}\n\n_disused static size_t MSSizeOfJump(uintptr_t target) {\n    return MSSizeOfJump(true, target);\n}\n\n_disused static size_t MSSizeOfJump(void *target, void *source) {\n    return MSSizeOfJump(reinterpret_cast<uintptr_t>(target), reinterpret_cast<uintptr_t>(source));\n}\n\n_disused static size_t MSSizeOfJump(void *target) {\n    return MSSizeOfJump(reinterpret_cast<uintptr_t>(target));\n}\n\n_disused static void MSWriteSkip(uint8_t *&current, ssize_t size) {\n    MSWrite<uint8_t>(current, 0xe9);\n    MSWrite<uint32_t>(current, size);\n}\n\n_disused static void MSPushPointer(uint8_t *&current, uintptr_t target) {\n    MSWrite<uint8_t>(current, 0x68);\n    MSWrite<uint32_t>(current, target);\n\n    if (uint32_t high = uint64_t(target) >> 32) {\n        MSWrite<uint8_t>(current, 0xc7);\n        MSWrite<uint8_t>(current, 0x44);\n        MSWrite<uint8_t>(current, 0x24);\n        MSWrite<uint8_t>(current, 0x04);\n        MSWrite<uint32_t>(current, high);\n    }\n}\n\n_disused static void MSPushPointer(uint8_t *&current, void *target) {\n    return MSPushPointer(current, reinterpret_cast<uintptr_t>(target));\n}\n\n_disused static void MSWriteCall(uint8_t *&current, I$r target) {\n    if (target >> 3 != 0)\n        MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3);\n    MSWrite<uint8_t>(current, 0xff);\n    MSWrite<uint8_t>(current, 0xd0 | target & 0x07);\n}\n\n_disused static void MSWriteCall(uint8_t *&current, uintptr_t target) {\n    uintptr_t source(reinterpret_cast<uintptr_t>(current));\n\n    if (ia32 || MSIs32BitOffset(target, source + 5)) {\n        MSWrite<uint8_t>(current, 0xe8);\n        MSWrite<uint32_t>(current, target - (source + 5));\n    } else {\n        MSPushPointer(current, target);\n\n        MSWrite<uint8_t>(current, 0x83);\n        MSWrite<uint8_t>(current, 0xc4);\n        MSWrite<uint8_t>(current, 0x08);\n\n        MSWrite<uint8_t>(current, 0x67);\n        MSWrite<uint8_t>(current, 0xff);\n        MSWrite<uint8_t>(current, 0x54);\n        MSWrite<uint8_t>(current, 0x24);\n        MSWrite<uint8_t>(current, 0xf8);\n    }\n}\n\ntemplate <typename Type_>\n_disused static void MSWriteCall(uint8_t *&current, Type_ *target) {\n    return MSWriteCall(current, reinterpret_cast<uintptr_t>(target));\n}\n\n_disused static void MSWriteJump(uint8_t *&current, uintptr_t target) {\n    uintptr_t source(reinterpret_cast<uintptr_t>(current));\n\n    if (ia32 || MSIs32BitOffset(target, source + 5))\n        MSWriteSkip(current, target - (source + 5));\n    else {\n        MSPushPointer(current, target);\n        MSWrite<uint8_t>(current, 0xc3);\n    }\n}\n\n_disused static void MSWriteJump(uint8_t *&current, void *target) {\n    return MSWriteJump(current, reinterpret_cast<uintptr_t>(target));\n}\n\n_disused static void MSWriteJump(uint8_t *&current, I$r target) {\n    if (target >> 3 != 0)\n        MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3);\n    MSWrite<uint8_t>(current, 0xff);\n    MSWrite<uint8_t>(current, 0xe0 | target & 0x07);\n}\n\n_disused static void MSWritePop(uint8_t *&current, uint8_t target) {\n    if (target >> 3 != 0)\n        MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3);\n    MSWrite<uint8_t>(current, 0x58 | target & 0x07);\n}\n\n_disused static size_t MSSizeOfPop(uint8_t target) {\n    return target >> 3 != 0 ? 2 : 1;\n}\n\n_disused static void MSWritePush(uint8_t *&current, I$r target) {\n    if (target >> 3 != 0)\n        MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3);\n    MSWrite<uint8_t>(current, 0x50 | target & 0x07);\n}\n\n_disused static void MSWriteAdd(uint8_t *&current, I$r target, uint8_t source) {\n    MSWrite<uint8_t>(current, 0x83);\n    MSWrite<uint8_t>(current, 0xc4 | target & 0x07);\n    MSWrite<uint8_t>(current, source);\n}\n\n_disused static void MSWriteSet64(uint8_t *&current, I$r target, uintptr_t source) {\n    MSWrite<uint8_t>(current, 0x48 | (target & 0x08) >> 3 << 2);\n    MSWrite<uint8_t>(current, 0xb8 | target & 0x7);\n    MSWrite<uint64_t>(current, source);\n}\n\ntemplate <typename Type_>\n_disused static void MSWriteSet64(uint8_t *&current, I$r target, Type_ *source) {\n    return MSWriteSet64(current, target, reinterpret_cast<uintptr_t>(source));\n}\n\n_disused static void MSWriteMove64(uint8_t *&current, uint8_t source, uint8_t target) {\n    MSWrite<uint8_t>(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3);\n    MSWrite<uint8_t>(current, 0x8b);\n    MSWrite<uint8_t>(current, (target & 0x07) << 3 | source & 0x07);\n}\n\n_disused static size_t MSSizeOfMove64() {\n    return 3;\n}\n\n#endif//SUBSTRATE_X86_HPP\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/hde64.c",
    "content": "/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"hde64.h\"\n#include \"table64.h\"\n\nunsigned int hde64_disasm(const void *code, hde64s *hs)\n{\n    uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;\n    uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;\n    uint8_t op64 = 0;\n\n    memset(hs,0,sizeof(hde64s));\n    char *tmp=(char*)hs;\n\n    for (x = 16; x; x--)\n        switch (c = *p++) {\n            case 0xf3:\n                hs->p_rep = c;\n                pref |= PRE_F3;\n                break;\n            case 0xf2:\n                hs->p_rep = c;\n                pref |= PRE_F2;\n                break;\n            case 0xf0:\n                hs->p_lock = c;\n                pref |= PRE_LOCK;\n                break;\n            case 0x26: case 0x2e: case 0x36:\n            case 0x3e: case 0x64: case 0x65:\n                hs->p_seg = c;\n                pref |= PRE_SEG;\n                break;\n            case 0x66:\n                hs->p_66 = c;\n                pref |= PRE_66;\n                break;\n            case 0x67:\n                hs->p_67 = c;\n                pref |= PRE_67;\n                break;\n            default:\n                goto pref_done;\n        }\n  pref_done:\n\n    hs->flags = (uint32_t)pref << 23;\n\n    if (!pref)\n        pref |= PRE_NONE;\n\n    if ((c & 0xf0) == 0x40) {\n        hs->flags |= F_PREFIX_REX;\n        if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)\n            op64++;\n        hs->rex_r = (c & 7) >> 2;\n        hs->rex_x = (c & 3) >> 1;\n        hs->rex_b = c & 1;\n        if (((c = *p++) & 0xf0) == 0x40) {\n            opcode = c;\n            goto error_opcode;\n        }\n    }\n\n    if ((hs->opcode = c) == 0x0f) {\n        hs->opcode2 = c = *p++;\n        ht += DELTA_OPCODES;\n    } else if (c >= 0xa0 && c <= 0xa3) {\n        op64++;\n        if (pref & PRE_67)\n            pref |= PRE_66;\n        else\n            pref &= ~PRE_66;\n    }\n\n    opcode = c;\n    cflags = ht[ht[opcode / 4] + (opcode % 4)];\n\n    if (cflags == C_ERROR) {\n      error_opcode:\n        hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        cflags = 0;\n        if ((opcode & -3) == 0x24)\n            cflags++;\n    }\n\n    x = 0;\n    if (cflags & C_GROUP) {\n        uint16_t t;\n        t = *(uint16_t *)(ht + (cflags & 0x7f));\n        cflags = (uint8_t)t;\n        x = (uint8_t)(t >> 8);\n    }\n\n    if (hs->opcode2) {\n        ht = hde64_table + DELTA_PREFIXES;\n        if (ht[ht[opcode / 4] + (opcode % 4)] & pref)\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n    }\n\n    if (cflags & C_MODRM) {\n        hs->flags |= F_MODRM;\n        hs->modrm = c = *p++;\n        hs->modrm_mod = m_mod = c >> 6;\n        hs->modrm_rm = m_rm = c & 7;\n        hs->modrm_reg = m_reg = (c & 0x3f) >> 3;\n\n        if (x && ((x << m_reg) & 0x80))\n            hs->flags |= F_ERROR | F_ERROR_OPCODE;\n\n        if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {\n            uint8_t t = opcode - 0xd9;\n            if (m_mod == 3) {\n                ht = hde64_table + DELTA_FPU_MODRM + t*8;\n                t = ht[m_reg] << m_rm;\n            } else {\n                ht = hde64_table + DELTA_FPU_REG;\n                t = ht[t] << m_reg;\n            }\n            if (t & 0x80)\n                hs->flags |= F_ERROR | F_ERROR_OPCODE;\n        }\n\n        if (pref & PRE_LOCK) {\n            if (m_mod == 3) {\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n            } else {\n                uint8_t *table_end, op = opcode;\n                if (hs->opcode2) {\n                    ht = hde64_table + DELTA_OP2_LOCK_OK;\n                    table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;\n                } else {\n                    ht = hde64_table + DELTA_OP_LOCK_OK;\n                    table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;\n                    op &= -2;\n                }\n                for (; ht != table_end; ht++)\n                    if (*ht++ == op) {\n                        if (!((*ht << m_reg) & 0x80))\n                            goto no_lock_error;\n                        else\n                            break;\n                    }\n                hs->flags |= F_ERROR | F_ERROR_LOCK;\n              no_lock_error:\n                ;\n            }\n        }\n\n        if (hs->opcode2) {\n            switch (opcode) {\n                case 0x20: case 0x22:\n                    m_mod = 3;\n                    if (m_reg > 4 || m_reg == 1)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x21: case 0x23:\n                    m_mod = 3;\n                    if (m_reg == 4 || m_reg == 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        } else {\n            switch (opcode) {\n                case 0x8c:\n                    if (m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n                case 0x8e:\n                    if (m_reg == 1 || m_reg > 5)\n                        goto error_operand;\n                    else\n                        goto no_error_operand;\n            }\n        }\n\n        if (m_mod == 3) {\n            uint8_t *table_end;\n            if (hs->opcode2) {\n                ht = hde64_table + DELTA_OP2_ONLY_MEM;\n                table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;\n            } else {\n                ht = hde64_table + DELTA_OP_ONLY_MEM;\n                table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;\n            }\n            for (; ht != table_end; ht += 2)\n                if (*ht++ == opcode) {\n                    if (*ht++ & pref && !((*ht << m_reg) & 0x80))\n                        goto error_operand;\n                    else\n                        break;\n                }\n            goto no_error_operand;\n        } else if (hs->opcode2) {\n            switch (opcode) {\n                case 0x50: case 0xd7: case 0xf7:\n                    if (pref & (PRE_NONE | PRE_66))\n                        goto error_operand;\n                    break;\n                case 0xd6:\n                    if (pref & (PRE_F2 | PRE_F3))\n                        goto error_operand;\n                    break;\n                case 0xc5:\n                    goto error_operand;\n            }\n            goto no_error_operand;\n        } else\n            goto no_error_operand;\n\n      error_operand:\n        hs->flags |= F_ERROR | F_ERROR_OPERAND;\n      no_error_operand:\n\n        c = *p++;\n        if (m_reg <= 1) {\n            if (opcode == 0xf6)\n                cflags |= C_IMM8;\n            else if (opcode == 0xf7)\n                cflags |= C_IMM_P66;\n        }\n\n        switch (m_mod) {\n            case 0:\n                if (pref & PRE_67) {\n                    if (m_rm == 6)\n                        disp_size = 2;\n                } else\n                    if (m_rm == 5)\n                        disp_size = 4;\n                break;\n            case 1:\n                disp_size = 1;\n                break;\n            case 2:\n                disp_size = 2;\n                if (!(pref & PRE_67))\n                    disp_size <<= 1;\n        }\n\n        if (m_mod != 3 && m_rm == 4) {\n            hs->flags |= F_SIB;\n            p++;\n            hs->sib = c;\n            hs->sib_scale = c >> 6;\n            hs->sib_index = (c & 0x3f) >> 3;\n            if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))\n                disp_size = 4;\n        }\n\n        p--;\n        switch (disp_size) {\n            case 1:\n                hs->flags |= F_DISP8;\n                hs->disp.disp8 = *p;\n                break;\n            case 2:\n                hs->flags |= F_DISP16;\n                hs->disp.disp16 = *(uint16_t *)p;\n                break;\n            case 4:\n                hs->flags |= F_DISP32;\n                hs->disp.disp32 = *(uint32_t *)p;\n        }\n        p += disp_size;\n    } else if (pref & PRE_LOCK)\n        hs->flags |= F_ERROR | F_ERROR_LOCK;\n\n    if (cflags & C_IMM_P66) {\n        if (cflags & C_REL32) {\n            if (pref & PRE_66) {\n                hs->flags |= F_IMM16 | F_RELATIVE;\n                hs->imm.imm16 = *(uint16_t *)p;\n                p += 2;\n                goto disasm_done;\n            }\n            goto rel32_ok;\n        }\n        if (op64) {\n            hs->flags |= F_IMM64;\n            hs->imm.imm64 = *(uint64_t *)p;\n            p += 8;\n        } else if (!(pref & PRE_66)) {\n            hs->flags |= F_IMM32;\n            hs->imm.imm32 = *(uint32_t *)p;\n            p += 4;\n        } else\n            goto imm16_ok;\n    }\n\n\n    if (cflags & C_IMM16) {\n      imm16_ok:\n        hs->flags |= F_IMM16;\n        hs->imm.imm16 = *(uint16_t *)p;\n        p += 2;\n    }\n    if (cflags & C_IMM8) {\n        hs->flags |= F_IMM8;\n        hs->imm.imm8 = *p++;\n    }\n\n    if (cflags & C_REL32) {\n      rel32_ok:\n        hs->flags |= F_IMM32 | F_RELATIVE;\n        hs->imm.imm32 = *(uint32_t *)p;\n        p += 4;\n    } else if (cflags & C_REL8) {\n        hs->flags |= F_IMM8 | F_RELATIVE;\n        hs->imm.imm8 = *p++;\n    }\n\n  disasm_done:\n\n    if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {\n        hs->flags |= F_ERROR | F_ERROR_LENGTH;\n        hs->len = 15;\n    }\n\n    return (unsigned int)hs->len;\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/hde64.h",
    "content": "/*\n * Hacker Disassembler Engine 64\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n * hde64.h: C/C++ header file\n *\n */\n\n#ifndef _HDE64_H_\n#define _HDE64_H_\n\n/* stdint.h - C99 standard header\n * http://en.wikipedia.org/wiki/stdint.h\n *\n * if your compiler doesn't contain \"stdint.h\" header (for\n * example, Microsoft Visual C++), you can download file:\n *   http://www.azillionmonkeys.com/qed/pstdint.h\n * and change next line to:\n *   #include \"pstdint.h\"\n */\n#include <stdint.h>\n\n#define F_MODRM         0x00000001\n#define F_SIB           0x00000002\n#define F_IMM8          0x00000004\n#define F_IMM16         0x00000008\n#define F_IMM32         0x00000010\n#define F_IMM64         0x00000020\n#define F_DISP8         0x00000040\n#define F_DISP16        0x00000080\n#define F_DISP32        0x00000100\n#define F_RELATIVE      0x00000200\n#define F_ERROR         0x00001000\n#define F_ERROR_OPCODE  0x00002000\n#define F_ERROR_LENGTH  0x00004000\n#define F_ERROR_LOCK    0x00008000\n#define F_ERROR_OPERAND 0x00010000\n#define F_PREFIX_REPNZ  0x01000000\n#define F_PREFIX_REPX   0x02000000\n#define F_PREFIX_REP    0x03000000\n#define F_PREFIX_66     0x04000000\n#define F_PREFIX_67     0x08000000\n#define F_PREFIX_LOCK   0x10000000\n#define F_PREFIX_SEG    0x20000000\n#define F_PREFIX_REX    0x40000000\n#define F_PREFIX_ANY    0x7f000000\n\n#define PREFIX_SEGMENT_CS   0x2e\n#define PREFIX_SEGMENT_SS   0x36\n#define PREFIX_SEGMENT_DS   0x3e\n#define PREFIX_SEGMENT_ES   0x26\n#define PREFIX_SEGMENT_FS   0x64\n#define PREFIX_SEGMENT_GS   0x65\n#define PREFIX_LOCK         0xf0\n#define PREFIX_REPNZ        0xf2\n#define PREFIX_REPX         0xf3\n#define PREFIX_OPERAND_SIZE 0x66\n#define PREFIX_ADDRESS_SIZE 0x67\n\n#pragma pack(push,1)\n\ntypedef struct {\n    uint8_t len;\n    uint8_t p_rep;\n    uint8_t p_lock;\n    uint8_t p_seg;\n    uint8_t p_66;\n    uint8_t p_67;\n    uint8_t rex;\n    uint8_t rex_w;\n    uint8_t rex_r;\n    uint8_t rex_x;\n    uint8_t rex_b; \n    uint8_t opcode;\n    uint8_t opcode2;\n    uint8_t modrm;\n    uint8_t modrm_mod;\n    uint8_t modrm_reg;\n    uint8_t modrm_rm;\n    uint8_t sib;\n    uint8_t sib_scale;\n    uint8_t sib_index;\n    uint8_t sib_base;\n    union {\n        uint8_t imm8;\n        uint16_t imm16;\n        uint32_t imm32;\n        uint64_t imm64;\n    } imm;\n    union {\n        uint8_t disp8;\n        uint16_t disp16;\n        uint32_t disp32;\n    } disp;\n    uint32_t flags;\n} hde64s;\n\n#pragma pack(pop)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* __cdecl */\nunsigned int hde64_disasm(const void *code, hde64s *hs);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _HDE64_H_ */\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/Substrate/table64.h",
    "content": "/*\n * Hacker Disassembler Engine 64 C\n * Copyright (c) 2008-2009, Vyacheslav Patkov.\n * All rights reserved.\n *\n */\n\n#define C_NONE    0x00\n#define C_MODRM   0x01\n#define C_IMM8    0x02\n#define C_IMM16   0x04\n#define C_IMM_P66 0x10\n#define C_REL8    0x20\n#define C_REL32   0x40\n#define C_GROUP   0x80\n#define C_ERROR   0xff\n\n#define PRE_ANY  0x00\n#define PRE_NONE 0x01\n#define PRE_F2   0x02\n#define PRE_F3   0x04\n#define PRE_66   0x08\n#define PRE_67   0x10\n#define PRE_LOCK 0x20\n#define PRE_SEG  0x40\n#define PRE_ALL  0xff\n\n#define DELTA_OPCODES      0x4a\n#define DELTA_FPU_REG      0xfd\n#define DELTA_FPU_MODRM    0x104\n#define DELTA_PREFIXES     0x13c\n#define DELTA_OP_LOCK_OK   0x1ae\n#define DELTA_OP2_LOCK_OK  0x1c6\n#define DELTA_OP_ONLY_MEM  0x1d8\n#define DELTA_OP2_ONLY_MEM 0x1e7\n\nunsigned char hde64_table[] = {\n  0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,\n  0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,\n  0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,\n  0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,\n  0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,\n  0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,\n  0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,\n  0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,\n  0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,\n  0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,\n  0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,\n  0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,\n  0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,\n  0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,\n  0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,\n  0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,\n  0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,\n  0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,\n  0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,\n  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,\n  0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,\n  0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,\n  0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,\n  0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,\n  0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,\n  0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,\n  0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,\n  0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,\n  0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,\n  0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,\n  0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,\n  0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,\n  0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,\n  0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,\n  0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,\n  0x00,0xf0,0x02,0x00\n};\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/Android.mk",
    "content": "LOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\n\nLOCAL_SRC_FILES:= \\\n       assert.cpp \\\n       jni/ByteBuffer.cpp \\\n       jni/Countable.cpp \\\n       jni/Environment.cpp \\\n       jni/Exceptions.cpp \\\n       jni/fbjni.cpp \\\n       jni/Hybrid.cpp \\\n       jni/jni_helpers.cpp \\\n       jni/LocalString.cpp \\\n       jni/OnLoad.cpp \\\n       jni/References.cpp \\\n       jni/WeakReference.cpp \\\n       log.cpp \\\n       lyra/lyra.cpp \\\n       onload.cpp \\\n\nLOCAL_C_INCLUDES := $(LOCAL_PATH)/include\nLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include\n\nLOCAL_CFLAGS := -DLOG_TAG=\\\"libfb\\\" -DDISABLE_CPUCAP -DDISABLE_XPLAT -fexceptions -frtti\nLOCAL_CFLAGS += -Wall -Werror\n# include/utils/threads.h has unused parameters\nLOCAL_CFLAGS += -Wno-unused-parameter\nifeq ($(TOOLCHAIN_PERMISSIVE),true)\n  LOCAL_CFLAGS += -Wno-error=unused-but-set-variable\nendif\nLOCAL_CFLAGS += -DHAVE_POSIX_CLOCKS\n\nCXX11_FLAGS := -std=gnu++11\nLOCAL_CFLAGS += $(CXX11_FLAGS)\n\nLOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)\n\nLOCAL_LDLIBS := -llog -ldl -landroid\nLOCAL_EXPORT_LDLIBS := -llog\n\nLOCAL_MODULE := libfb\n\ninclude $(BUILD_STATIC_LIBRARY)\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/BUCK",
    "content": "include_defs(\"//ReactAndroid/DEFS\")\n\n# This target is only used in open source\nif IS_OSS_BUILD:\n  cxx_library(\n    name = 'jni',\n    soname = 'libfb.$(ext)',\n    srcs = glob(['*.cpp', 'jni/*.cpp', 'lyra/*.cpp']),\n    header_namespace = '',\n    compiler_flags = [\n      '-fno-omit-frame-pointer',\n      '-fexceptions',\n      '-Wall',\n      '-Werror',\n      '-std=c++11',\n      '-DDISABLE_CPUCAP',\n      '-DDISABLE_XPLAT',\n    ],\n    exported_headers = subdir_glob([\n      ('include', 'fb/**/*.h'),\n      ('include', 'jni/*.h'),\n    ]),\n    deps = [\n      JNI_TARGET,\n    ],\n    visibility = ['PUBLIC'],\n  )\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/Doxyfile",
    "content": "PROJECT_NAME           = \"Facebook Android Support\"\nJAVADOC_AUTOBRIEF      = YES\nEXTRACT_ALL            = YES\nRECURSIVE              = YES\nEXCLUDE                = tests\nEXCLUDE_PATTERNS       = *.cpp\nGENERATE_HTML          = YES\nGENERATE_LATEX         = NO\nENABLE_PREPROCESSING   = YES\nHIDE_UNDOC_MEMBERS     = YES\nHIDE_SCOPE_NAMES       = YES\nHIDE_FRIEND_COMPOUNDS  = YES\nHIDE_UNDOC_CLASSES     = YES\nSHOW_INCLUDE_FILES     = NO\n#ENABLED_SECTIONS       = INTERNAL\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/assert.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <cstdarg>\n#include <stdio.h>\n\n#include <fb/assert.h>\n#include <fb/log.h>\n\nnamespace facebook {\n\n#define ASSERT_BUF_SIZE 4096\nstatic char sAssertBuf[ASSERT_BUF_SIZE];\nstatic AssertHandler gAssertHandler;\n\nvoid assertInternal(const char* formatstr ...) {\n    va_list va_args;\n    va_start(va_args, formatstr);\n    vsnprintf(sAssertBuf, sizeof(sAssertBuf), formatstr, va_args);\n    va_end(va_args);\n    if (gAssertHandler != NULL) {\n        gAssertHandler(sAssertBuf);\n    }\n    FBLOG(LOG_FATAL, \"fbassert\", \"%s\", sAssertBuf);\n    // crash at this specific address so that we can find our crashes easier\n    *(int*)0xdeadb00c = 0;\n    // let the compiler know we won't reach the end of the function\n     __builtin_unreachable();\n}\n\nvoid setAssertHandler(AssertHandler assertHandler) {\n    gAssertHandler = assertHandler;\n}\n\n} // namespace facebook\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/ALog.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n/** @file ALog.h\n *\n *  Very simple android only logging. Define LOG_TAG to enable the macros.\n */\n\n#pragma once\n\n\n#ifdef __ANDROID__\n\n#include <android/log.h>\n\nnamespace facebook {\nnamespace alog {\n\ntemplate<typename... ARGS>\ninline void log(int level, const char* tag, const char* msg, ARGS... args) noexcept {\n  __android_log_print(level, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void log(int level, const char* tag, const char* msg) noexcept {\n  __android_log_write(level, tag, msg);\n}\n\ntemplate<typename... ARGS>\ninline void logv(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_VERBOSE, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void logd(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_DEBUG, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void logi(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_INFO, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void logw(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_WARN, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void loge(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_ERROR, tag, msg, args...);\n}\n\ntemplate<typename... ARGS>\ninline void logf(const char* tag, const char* msg, ARGS... args) noexcept {\n  log(ANDROID_LOG_FATAL, tag, msg, args...);\n}\n\n\n#ifdef LOG_TAG\n# define ALOGV(...) ::facebook::alog::logv(LOG_TAG, __VA_ARGS__)\n# define ALOGD(...) ::facebook::alog::logd(LOG_TAG, __VA_ARGS__)\n# define ALOGI(...) ::facebook::alog::logi(LOG_TAG, __VA_ARGS__)\n# define ALOGW(...) ::facebook::alog::logw(LOG_TAG, __VA_ARGS__)\n# define ALOGE(...) ::facebook::alog::loge(LOG_TAG, __VA_ARGS__)\n# define ALOGF(...) ::facebook::alog::logf(LOG_TAG, __VA_ARGS__)\n#endif\n\n}}\n\n#else\n# define ALOGV(...) ((void)0)\n# define ALOGD(...) ((void)0)\n# define ALOGI(...) ((void)0)\n# define ALOGW(...) ((void)0)\n# define ALOGE(...) ((void)0)\n# define ALOGF(...) ((void)0)\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/Build.h",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#pragma once\n\n#include <stdlib.h>\n\n#if defined(__ANDROID__)\n#  include <sys/system_properties.h>\n#endif\n\nnamespace facebook {\nnamespace build {\n\nstruct Build {\n  static int getAndroidSdk() {\n    static auto android_sdk = ([] {\n       char sdk_version_str[PROP_VALUE_MAX];\n       __system_property_get(\"ro.build.version.sdk\", sdk_version_str);\n       return atoi(sdk_version_str);\n    })();\n    return android_sdk;\n  }\n};\n\n} // build\n} // facebook\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/Countable.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <atomic>\n#include <fb/assert.h>\n#include <fb/noncopyable.h>\n#include <fb/nonmovable.h>\n#include <fb/RefPtr.h>\n\nnamespace facebook {\n\nclass Countable : public noncopyable, public nonmovable {\npublic:\n  // RefPtr expects refcount to start at 0\n  Countable() : m_refcount(0) {}\n  virtual ~Countable()\n  {\n    FBASSERT(m_refcount == 0);\n  }\n\nprivate:\n  void ref() {\n    ++m_refcount;\n  }\n\n  void unref() {\n    if (0 == --m_refcount) {\n      delete this;\n    }\n  }\n\n  bool hasOnlyOneRef() const {\n    return m_refcount == 1;\n  }\n\n  template <typename T> friend class RefPtr;\n  std::atomic<int> m_refcount;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/Doxyfile",
    "content": "PROJECT_NAME           = \"Facebook JNI\"\nPROJECT_BRIEF          = \"Helper library to provide safe and convenient access to JNI with very low overhead\"\nJAVADOC_AUTOBRIEF      = YES\nEXTRACT_ALL            = YES\nRECURSIVE              = YES\nEXCLUDE                = tests Asserts.h Countable.h GlobalReference.h LocalReference.h LocalString.h Registration.h WeakReference.h jni_helpers.h Environment.h\nEXCLUDE_PATTERNS       = *-inl.h *.cpp\nGENERATE_HTML          = YES\nGENERATE_LATEX         = NO\nENABLE_PREPROCESSING   = YES\nHIDE_UNDOC_MEMBERS     = YES\nHIDE_SCOPE_NAMES       = YES\nHIDE_FRIEND_COMPOUNDS  = YES\nHIDE_UNDOC_CLASSES     = YES\nSHOW_INCLUDE_FILES     = NO\nPREDEFINED             = LOG_TAG=fbjni\nEXAMPLE_PATH           = samples\n#ENABLED_SECTIONS       = INTERNAL\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/Environment.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <functional>\n#include <string>\n#include <jni.h>\n\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace internal {\n  struct CacheEnvTag {};\n}\n\n// Keeps a thread-local reference to the current thread's JNIEnv.\nstruct Environment {\n  // May be null if this thread isn't attached to the JVM\n  FBEXPORT static JNIEnv* current();\n  static void initialize(JavaVM* vm);\n\n  // There are subtle issues with calling the next functions directly. It is\n  // much better to always use a ThreadScope to manage attaching/detaching for\n  // you.\n  FBEXPORT static JNIEnv* ensureCurrentThreadIsAttached();\n  FBEXPORT static void detachCurrentThread();\n};\n\n/**\n * RAII Object that attaches a thread to the JVM. Failing to detach from a thread before it\n * exits will cause a crash, as will calling Detach an extra time, and this guard class helps\n * keep that straight. In addition, it remembers whether it performed the attach or not, so it\n * is safe to nest it with itself or with non-fbjni code that manages the attachment correctly.\n *\n * Potential concerns:\n *  - Attaching to the JVM is fast (~100us on MotoG), but ideally you would attach while the\n *    app is not busy.\n *  - Having a thread detach at arbitrary points is not safe in Dalvik; you need to be sure that\n *    there is no Java code on the current stack or you run the risk of a crash like:\n *      ERROR: detaching thread with interp frames (count=18)\n *    (More detail at https://groups.google.com/forum/#!topic/android-ndk/2H8z5grNqjo)\n *    ThreadScope won't do a detach if the thread was already attached before the guard is\n *    instantiated, but there's probably some usage that could trip this up.\n *  - Newly attached C++ threads only get the bootstrap class loader -- i.e. java language\n *    classes, not any of our application's classes. This will be different behavior than threads\n *    that were initiated on the Java side. A workaround is to pass a global reference for a\n *    class or instance to the new thread; this bypasses the need for the class loader.\n *    (See http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread)\n *    If you need access to the application's classes, you can use ThreadScope::WithClassLoader.\n */\nclass FBEXPORT ThreadScope {\n public:\n  ThreadScope();\n  ThreadScope(ThreadScope&) = delete;\n  ThreadScope(ThreadScope&&) = default;\n  ThreadScope& operator=(ThreadScope&) = delete;\n  ThreadScope& operator=(ThreadScope&&) = delete;\n  ~ThreadScope();\n\n  /**\n   * This runs the closure in a scope with fbjni's classloader. This should be\n   * the same classloader as the rest of the application and thus anything\n   * running in the closure will have access to the same classes as in a normal\n   * java-create thread.\n   */\n  static void WithClassLoader(std::function<void()>&& runnable);\n\n  static void OnLoad();\n\n  // This constructor is only used internally by fbjni.\n  ThreadScope(JNIEnv*, internal::CacheEnvTag);\n private:\n  friend struct Environment;\n  ThreadScope* previous_;\n  // If the JNIEnv* is set, it is guaranteed to be valid at least through the\n  // lifetime of this ThreadScope. The only case where that guarantee can be\n  // made is when there is a java frame in the stack below this.\n  JNIEnv* env_;\n  bool attachedWithThisScope_;\n};\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/ProgramLocation.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <cstring>\n#include <string>\n#include <sstream>\n\nnamespace facebook {\n\n#define FROM_HERE facebook::ProgramLocation(__FUNCTION__, __FILE__, __LINE__)\n\nclass ProgramLocation {\npublic:\n  ProgramLocation() : m_functionName(\"Unspecified\"), m_fileName(\"Unspecified\"), m_lineNumber(0) {}\n\n  ProgramLocation(const char* functionName, const char* fileName, int line) :\n      m_functionName(functionName),\n      m_fileName(fileName),\n      m_lineNumber(line)\n    {}\n\n  const char* functionName() const { return m_functionName; }\n  const char* fileName() const { return m_fileName; }\n  int lineNumber() const { return m_lineNumber; }\n\n  std::string asFormattedString() const {\n    std::stringstream str;\n    str << \"Function \" << m_functionName << \" in file \" << m_fileName << \":\" << m_lineNumber;\n    return str.str();\n  }\n\n  bool operator==(const ProgramLocation& other) const {\n    // Assumes that the strings are static\n    return (m_functionName == other.m_functionName) && (m_fileName == other.m_fileName) && m_lineNumber == other.m_lineNumber;\n  }\n\nprivate:\n  const char* m_functionName;\n  const char* m_fileName;\n  int m_lineNumber;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/RefPtr.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <utility>\n#include <fb/assert.h>\n\nnamespace facebook {\n\n// Reference counting smart pointer. This is designed to work with the\n// Countable class or other implementations in the future. It is designed in a\n// way to be both efficient and difficult to misuse. Typical usage is very\n// simple once you learn the patterns (and the compiler will help!):\n//\n// By default, the internal pointer is null.\n//   RefPtr<Foo> ref;\n//\n// Object creation requires explicit construction:\n//   RefPtr<Foo> ref = createNew<Foo>(...);\n//\n// Or if the constructor is not public:\n//   RefPtr<Foo> ref = adoptRef(new Foo(...));\n//\n// But you can implicitly create from nullptr:\n//   RefPtr<Foo> maybeRef = cond ? ref : nullptr;\n//\n// Move/Copy Construction/Assignment are straightforward:\n//   RefPtr<Foo> ref2 = ref;\n//   ref = std::move(ref2);\n//\n// Destruction automatically drops the RefPtr's reference as expected.\n//\n// Upcasting is implicit but downcasting requires an explicit cast:\n//   struct Bar : public Foo {};\n//   RefPtr<Bar> barRef = static_cast<RefPtr<Bar>>(ref);\n//   ref = barRef;\n//\ntemplate <class T>\nclass RefPtr {\npublic:\n  constexpr RefPtr() :\n    m_ptr(nullptr)\n  {}\n\n  // Allow implicit construction from a pointer only from nullptr\n  constexpr RefPtr(std::nullptr_t ptr) :\n    m_ptr(nullptr)\n  {}\n\n  RefPtr(const RefPtr<T>& ref) :\n    m_ptr(ref.m_ptr)\n  {\n    refIfNecessary(m_ptr);\n  }\n\n  // Only allow implicit upcasts. A downcast will result in a compile error\n  // unless you use static_cast (which will end up invoking the explicit\n  // operator below).\n  template <typename U>\n  RefPtr(const RefPtr<U>& ref, typename std::enable_if<std::is_base_of<T,U>::value, U>::type* = nullptr) :\n    m_ptr(ref.get())\n  {\n    refIfNecessary(m_ptr);\n  }\n\n  RefPtr(RefPtr<T>&& ref) :\n    m_ptr(nullptr)\n  {\n    *this = std::move(ref);\n  }\n\n  // Only allow implicit upcasts. A downcast will result in a compile error\n  // unless you use static_cast (which will end up invoking the explicit\n  // operator below).\n  template <typename U>\n  RefPtr(RefPtr<U>&& ref, typename std::enable_if<std::is_base_of<T,U>::value, U>::type* = nullptr) :\n    m_ptr(nullptr)\n  {\n    *this = std::move(ref);\n  }\n\n  ~RefPtr() {\n    unrefIfNecessary(m_ptr);\n    m_ptr = nullptr;\n  }\n\n  RefPtr<T>& operator=(const RefPtr<T>& ref) {\n    if (m_ptr != ref.m_ptr) {\n      unrefIfNecessary(m_ptr);\n      m_ptr = ref.m_ptr;\n      refIfNecessary(m_ptr);\n    }\n    return *this;\n  }\n\n  // The STL assumes rvalue references are unique and for simplicity's sake, we\n  // make the same assumption here, that &ref != this.\n  RefPtr<T>& operator=(RefPtr<T>&& ref) {\n    unrefIfNecessary(m_ptr);\n    m_ptr = ref.m_ptr;\n    ref.m_ptr = nullptr;\n    return *this;\n  }\n\n  template <typename U>\n  RefPtr<T>& operator=(RefPtr<U>&& ref) {\n    unrefIfNecessary(m_ptr);\n    m_ptr = ref.m_ptr;\n    ref.m_ptr = nullptr;\n    return *this;\n  }\n\n  void reset() {\n    unrefIfNecessary(m_ptr);\n    m_ptr = nullptr;\n  }\n\n  T* get() const {\n    return m_ptr;\n  }\n\n  T* operator->() const {\n    return m_ptr;\n  }\n\n  T& operator*() const {\n    return *m_ptr;\n  }\n\n  template <typename U>\n  explicit operator RefPtr<U> () const;\n\n  explicit operator bool() const {\n    return m_ptr ? true : false;\n  }\n\n  bool isTheLastRef() const {\n    FBASSERT(m_ptr);\n    return m_ptr->hasOnlyOneRef();\n  }\n\n  // Creates a strong reference from a raw pointer, assuming that is already\n  // referenced from some other RefPtr. This should be used sparingly.\n  static inline RefPtr<T> assumeAlreadyReffed(T* ptr) {\n    return RefPtr<T>(ptr, ConstructionMode::External);\n  }\n\n  // Creates a strong reference from a raw pointer, assuming that it points to a\n  // freshly-created object. See the documentation for RefPtr for usage.\n  static inline RefPtr<T> adoptRef(T* ptr) {\n    return RefPtr<T>(ptr, ConstructionMode::Adopted);\n  }\n\nprivate:\n  enum class ConstructionMode {\n    Adopted,\n    External\n  };\n\n  RefPtr(T* ptr, ConstructionMode mode) :\n    m_ptr(ptr)\n  {\n    FBASSERTMSGF(ptr, \"Got null pointer in %s construction mode\", mode == ConstructionMode::Adopted ? \"adopted\" : \"external\");\n    ptr->ref();\n    if (mode == ConstructionMode::Adopted) {\n      FBASSERT(ptr->hasOnlyOneRef());\n    }\n  }\n\n  static inline void refIfNecessary(T* ptr) {\n    if (ptr) {\n      ptr->ref();\n    }\n  }\n  static inline void unrefIfNecessary(T* ptr) {\n    if (ptr) {\n      ptr->unref();\n    }\n  }\n\n  template <typename U> friend class RefPtr;\n\n  T* m_ptr;\n};\n\n// Creates a strong reference from a raw pointer, assuming that is already\n// referenced from some other RefPtr and that it is non-null. This should be\n// used sparingly.\ntemplate <typename T>\nstatic inline RefPtr<T> assumeAlreadyReffed(T* ptr) {\n  return RefPtr<T>::assumeAlreadyReffed(ptr);\n}\n\n// As above, but tolerant of nullptr.\ntemplate <typename T>\nstatic inline RefPtr<T> assumeAlreadyReffedOrNull(T* ptr) {\n  return ptr ? RefPtr<T>::assumeAlreadyReffed(ptr) : nullptr;\n}\n\n// Creates a strong reference from a raw pointer, assuming that it points to a\n// freshly-created object. See the documentation for RefPtr for usage.\ntemplate <typename T>\nstatic inline RefPtr<T> adoptRef(T* ptr) {\n  return RefPtr<T>::adoptRef(ptr);\n}\n\ntemplate <typename T, typename ...Args>\nstatic inline RefPtr<T> createNew(Args&&... arguments) {\n  return RefPtr<T>::adoptRef(new T(std::forward<Args>(arguments)...));\n}\n\ntemplate <typename T> template <typename U>\nRefPtr<T>::operator RefPtr<U>() const {\n  static_assert(std::is_base_of<T, U>::value, \"Invalid static cast\");\n  return assumeAlreadyReffedOrNull<U>(static_cast<U*>(m_ptr));\n}\n\ntemplate <typename T, typename U>\ninline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b) {\n  return a.get() == b.get();\n}\n\ntemplate <typename T, typename U>\ninline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b) {\n  return a.get() != b.get();\n}\n\ntemplate <typename T, typename U>\ninline bool operator==(const RefPtr<T>& ref, U* ptr) {\n  return ref.get() == ptr;\n}\n\ntemplate <typename T, typename U>\ninline bool operator!=(const RefPtr<T>& ref, U* ptr) {\n  return ref.get() != ptr;\n}\n\ntemplate <typename T, typename U>\ninline bool operator==(U* ptr, const RefPtr<T>& ref) {\n  return ref.get() == ptr;\n}\n\ntemplate <typename T, typename U>\ninline bool operator!=(U* ptr, const RefPtr<T>& ref) {\n  return ref.get() != ptr;\n}\n\ntemplate <typename T>\ninline bool operator==(const RefPtr<T>& ref, std::nullptr_t ptr) {\n  return ref.get() == ptr;\n}\n\ntemplate <typename T>\ninline bool operator!=(const RefPtr<T>& ref, std::nullptr_t ptr) {\n  return ref.get() != ptr;\n}\n\ntemplate <typename T>\ninline bool operator==(std::nullptr_t ptr, const RefPtr<T>& ref) {\n  return ref.get() == ptr;\n}\n\ntemplate <typename T>\ninline bool operator!=(std::nullptr_t ptr, const RefPtr<T>& ref) {\n  return ref.get() != ptr;\n}\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/StaticInitialized.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <fb/assert.h>\n#include <utility>\n\nnamespace facebook {\n\n// Class that lets you declare a global but does not add a static constructor\n// to the binary. Eventually I'd like to have this auto-initialize in a\n// multithreaded environment but for now it's easiest just to use manual\n// initialization.\ntemplate <typename T>\nclass StaticInitialized {\npublic:\n  constexpr StaticInitialized() :\n    m_instance(nullptr)\n  {}\n\n  template <typename ...Args>\n  void initialize(Args&&... arguments) {\n    FBASSERT(!m_instance);\n    m_instance = new T(std::forward<Args>(arguments)...);\n  }\n\n  T* operator->() const {\n    return m_instance;\n  }\nprivate:\n  T* m_instance;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/ThreadLocal.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <pthread.h>\n#include <errno.h>\n\n#include <fb/assert.h>\n\nnamespace facebook {\n\n///////////////////////////////////////////////////////////////////////////////\n\n/**\n * A thread-local object is a \"global\" object within a thread. This is useful\n * for writing apartment-threaded code, where nothing is actullay shared\n * between different threads (hence no locking) but those variables are not\n * on stack in local scope. To use it, just do something like this,\n *\n *   ThreadLocal<MyClass> static_object;\n *     static_object->data_ = ...;\n *     static_object->doSomething();\n *\n *   ThreadLocal<int> static_number;\n *     int value = *static_number;\n *\n * So, syntax-wise it's similar to pointers. T can be primitive types, and if\n * it's a class, there has to be a default constructor.\n */\ntemplate<typename T>\nclass ThreadLocal {\npublic:\n  /**\n   * Constructor that has to be called from a thread-neutral place.\n   */\n  ThreadLocal() :\n    m_key(0),\n    m_cleanup(OnThreadExit) {\n    initialize();\n  }\n\n  /**\n   * As above but with a custom cleanup function\n   */\n  typedef void (*CleanupFunction)(void* obj);\n  explicit ThreadLocal(CleanupFunction cleanup) :\n    m_key(0),\n    m_cleanup(cleanup) {\n    FBASSERT(cleanup);\n    initialize();\n  }\n\n  /**\n   * Access object's member or method through this operator overload.\n   */\n  T *operator->() const {\n    return get();\n  }\n\n  T &operator*() const {\n    return *get();\n  }\n\n  T *get() const {\n    return (T*)pthread_getspecific(m_key);\n  }\n\n  T* release() {\n    T* obj = get();\n    pthread_setspecific(m_key, NULL);\n    return obj;\n  }\n\n  void reset(T* other = NULL) {\n    T* old = (T*)pthread_getspecific(m_key);\n    if (old != other) {\n      FBASSERT(m_cleanup);\n      m_cleanup(old);\n      pthread_setspecific(m_key, other);\n    }\n  }\n\nprivate:\n  void initialize() {\n    int ret = pthread_key_create(&m_key, m_cleanup);\n    if (ret != 0) {\n      const char *msg = \"(unknown error)\";\n      switch (ret) {\n      case EAGAIN:\n        msg = \"PTHREAD_KEYS_MAX (1024) is exceeded\";\n        break;\n      case ENOMEM:\n        msg = \"Out-of-memory\";\n        break;\n      }\n      (void) msg;\n      FBASSERTMSGF(0, \"pthread_key_create failed: %d %s\", ret, msg);\n    }\n  }\n\n  static void OnThreadExit(void *obj) {\n    if (NULL != obj) {\n      delete (T*)obj;\n    }\n  }\n\n  pthread_key_t m_key;\n  CleanupFunction m_cleanup;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/assert.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#ifndef FBASSERT_H\n#define FBASSERT_H\n\n#include <fb/visibility.h>\n\nnamespace facebook {\n#define ENABLE_FBASSERT 1\n\n#if ENABLE_FBASSERT\n#define FBASSERTMSGF(expr, msg, ...) !(expr) ? facebook::assertInternal(\"Assert (%s:%d): \" msg, __FILE__, __LINE__, ##__VA_ARGS__) : (void) 0\n#else\n#define FBASSERTMSGF(expr, msg, ...)\n#endif // ENABLE_FBASSERT\n\n#define FBASSERT(expr) FBASSERTMSGF(expr, \"%s\", #expr)\n\n#define FBCRASH(msg, ...) facebook::assertInternal(\"Fatal error (%s:%d): \" msg, __FILE__, __LINE__, ##__VA_ARGS__)\n#define FBUNREACHABLE() facebook::assertInternal(\"This code should be unreachable (%s:%d)\", __FILE__, __LINE__)\n\nFBEXPORT void assertInternal(const char* formatstr, ...) __attribute__((noreturn));\n\n// This allows storing the assert message before the current process terminates due to a crash\ntypedef void (*AssertHandler)(const char* message);\nvoid setAssertHandler(AssertHandler assertHandler);\n\n} // namespace facebook\n#endif // FBASSERT_H\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Boxed.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\ntemplate <typename T, typename jprim>\nstruct JPrimitive : JavaClass<T> {\n  using typename JavaClass<T>::javaobject;\n  using JavaClass<T>::javaClassStatic;\n  static local_ref<javaobject> valueOf(jprim val) {\n    static auto cls = javaClassStatic();\n    static auto method =\n      cls->template getStaticMethod<javaobject(jprim)>(\"valueOf\");\n    return method(cls, val);\n  }\n  jprim value() const {\n    static auto method =\n      javaClassStatic()->template getMethod<jprim()>(T::kValueMethod);\n    return method(this->self());\n  }\n};\n\n} // namespace detail\n\n\n#define DEFINE_BOXED_PRIMITIVE(LITTLE, BIG)                          \\\n  struct J ## BIG : detail::JPrimitive<J ## BIG, j ## LITTLE> {      \\\n    static auto constexpr kJavaDescriptor = \"Ljava/lang/\" #BIG \";\";  \\\n    static auto constexpr kValueMethod = #LITTLE \"Value\";            \\\n    j ## LITTLE LITTLE ## Value() const {                            \\\n      return value();                                                \\\n    }                                                                \\\n  };                                                                 \\\n  inline local_ref<jobject> autobox(j ## LITTLE val) {               \\\n    return J ## BIG::valueOf(val);                                   \\\n  }\n\nDEFINE_BOXED_PRIMITIVE(boolean, Boolean)\nDEFINE_BOXED_PRIMITIVE(byte, Byte)\nDEFINE_BOXED_PRIMITIVE(char, Character)\nDEFINE_BOXED_PRIMITIVE(short, Short)\nDEFINE_BOXED_PRIMITIVE(int, Integer)\nDEFINE_BOXED_PRIMITIVE(long, Long)\nDEFINE_BOXED_PRIMITIVE(float, Float)\nDEFINE_BOXED_PRIMITIVE(double, Double)\n\n#undef DEFINE_BOXED_PRIMITIVE\n\nstruct JVoid : public jni::JavaClass<JVoid> {\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/Void;\";\n};\n\ninline local_ref<jobject> autobox(alias_ref<jobject> val) {\n  return make_local(val);\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/ByteBuffer.h",
    "content": "/*\n * Copyright (c) 2016-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <fb/visibility.h>\n\n#include \"CoreClasses.h\"\n#include \"References-forward.h\"\n\nnamespace facebook {\nnamespace jni {\n\n// JNI's NIO support has some awkward preconditions and error reporting. This\n// class provides much more user-friendly access.\nclass FBEXPORT JByteBuffer : public JavaClass<JByteBuffer> {\n public:\n  static constexpr const char* kJavaDescriptor = \"Ljava/nio/ByteBuffer;\";\n\n  static local_ref<JByteBuffer> wrapBytes(uint8_t* data, size_t size);\n\n  bool isDirect() const;\n\n  uint8_t* getDirectBytes() const;\n  size_t getDirectSize() const;\n};\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Common.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n/** @file Common.h\n *\n * Defining the stuff that don't deserve headers of their own...\n */\n\n#pragma once\n\n#include <functional>\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n#include <fb/Environment.h>\n\n#ifdef FBJNI_DEBUG_REFS\n# ifdef __ANDROID__\n#  include <android/log.h>\n# else\n#  include <cstdio>\n# endif\n#endif\n\n// If a pending JNI Java exception is found, wraps it in a JniException object and throws it as\n// a C++ exception.\n#define FACEBOOK_JNI_THROW_PENDING_EXCEPTION() \\\n  ::facebook::jni::throwPendingJniExceptionAsCppException()\n\n// If the condition is true, throws a JniException object, which wraps the pending JNI Java\n// exception if any. If no pending exception is found, throws a JniException object that wraps a\n// RuntimeException throwable. \n#define FACEBOOK_JNI_THROW_EXCEPTION_IF(CONDITION) \\\n  ::facebook::jni::throwCppExceptionIf(CONDITION)\n\n/// @cond INTERNAL\n\nnamespace facebook {\nnamespace jni {\n\nFBEXPORT void throwPendingJniExceptionAsCppException();\nFBEXPORT void throwCppExceptionIf(bool condition);\n\n[[noreturn]] FBEXPORT void throwNewJavaException(jthrowable);\n[[noreturn]] FBEXPORT void throwNewJavaException(const char* throwableName, const char* msg);\ntemplate<typename... Args>\n[[noreturn]] void throwNewJavaException(const char* throwableName, const char* fmt, Args... args);\n\n\n/**\n * This needs to be called at library load time, typically in your JNI_OnLoad method.\n *\n * The intended use is to return the result of initialize() directly\n * from JNI_OnLoad and to do nothing else there. Library specific\n * initialization code should go in the function passed to initialize\n * (which can be, and probably should be, a C++ lambda). This approach\n * provides correct error handling and translation errors during\n * initialization into Java exceptions when appropriate.\n *\n * Failure to call this will cause your code to crash in a remarkably\n * unhelpful way (typically a segfault) while trying to handle an exception\n * which occurs later.\n */\nFBEXPORT jint initialize(JavaVM*, std::function<void()>&&) noexcept;\n\nnamespace internal {\n\n/**\n * Retrieve a pointer the JNI environment of the current thread.\n *\n * @pre The current thread must be attached to the VM\n */\ninline JNIEnv* getEnv() noexcept {\n  // TODO(T6594868) Benchmark against raw JNI access\n  return Environment::current();\n}\n\n// Define to get extremely verbose logging of references and to enable reference stats\n#ifdef FBJNI_DEBUG_REFS\ntemplate<typename... Args>\ninline void dbglog(const char* msg, Args... args) {\n# ifdef __ANDROID__\n  __android_log_print(ANDROID_LOG_VERBOSE, \"fbjni_dbg\", msg, args...);\n# else\n  std::fprintf(stderr, msg, args...);\n# endif\n}\n\n#else\n\ntemplate<typename... Args>\ninline void dbglog(const char*, Args...) {\n}\n\n#endif\n\n}}}\n\n/// @endcond\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Context.h",
    "content": "/*\n * Copyright (c) 2016-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n#include \"File.h\"\n\nnamespace facebook {\nnamespace jni {\n\nclass AContext : public JavaClass<AContext> {\n public:\n  static constexpr const char* kJavaDescriptor = \"Landroid/content/Context;\";\n\n  // Define a method that calls into the represented Java class\n  local_ref<JFile::javaobject> getCacheDir() {\n    static auto method = getClass()->getMethod<JFile::javaobject()>(\"getCacheDir\");\n    return method(self());\n  }\n\n  local_ref<JFile::javaobject> getFilesDir() {\n    static auto method = getClass()->getMethod<JFile::javaobject()>(\"getFilesDir\");\n    return method(self());\n  }\n};\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/CoreClasses-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <string.h>\n#include <type_traits>\n#include <stdlib.h>\n\n#include \"Common.h\"\n#include \"Exceptions.h\"\n#include \"Meta.h\"\n#include \"MetaConvert.h\"\n\nnamespace facebook {\nnamespace jni {\n\n// jobject /////////////////////////////////////////////////////////////////////////////////////////\n\ninline bool isSameObject(alias_ref<JObject> lhs, alias_ref<JObject> rhs) noexcept {\n  return internal::getEnv()->IsSameObject(lhs.get(), rhs.get()) != JNI_FALSE;\n}\n\ninline local_ref<JClass> JObject::getClass() const noexcept {\n  return adopt_local(internal::getEnv()->GetObjectClass(self()));\n}\n\ninline bool JObject::isInstanceOf(alias_ref<JClass> cls) const noexcept {\n  return internal::getEnv()->IsInstanceOf(self(), cls.get()) != JNI_FALSE;\n}\n\ntemplate<typename T>\ninline T JObject::getFieldValue(JField<T> field) const noexcept {\n  return field.get(self());\n}\n\ntemplate<typename T>\ninline local_ref<T*> JObject::getFieldValue(JField<T*> field) const noexcept {\n  return adopt_local(field.get(self()));\n}\n\ntemplate<typename T>\ninline void JObject::setFieldValue(JField<T> field, T value) noexcept {\n  field.set(self(), value);\n}\n\ninline std::string JObject::toString() const {\n  static auto method = findClassLocal(\"java/lang/Object\")->getMethod<jstring()>(\"toString\");\n\n  return method(self())->toStdString();\n}\n\n\n// Class is here instead of CoreClasses.h because we need\n// alias_ref to be complete.\nclass MonitorLock {\n public:\n  inline MonitorLock() noexcept;\n  inline MonitorLock(alias_ref<JObject> object) noexcept;\n  inline ~MonitorLock() noexcept;\n\n  inline MonitorLock(MonitorLock&& other) noexcept;\n  inline MonitorLock& operator=(MonitorLock&& other) noexcept;\n\n  inline MonitorLock(const MonitorLock&) = delete;\n  inline MonitorLock& operator=(const MonitorLock&) = delete;\n\n private:\n  inline void reset() noexcept;\n  alias_ref<JObject> owned_;\n};\n\nMonitorLock::MonitorLock() noexcept : owned_(nullptr) {}\n\nMonitorLock::MonitorLock(alias_ref<JObject> object) noexcept\n    : owned_(object) {\n  internal::getEnv()->MonitorEnter(object.get());\n}\n\nvoid MonitorLock::reset() noexcept {\n  if (owned_) {\n    internal::getEnv()->MonitorExit(owned_.get());\n    if (internal::getEnv()->ExceptionCheck()) {\n      abort(); // Lock mismatch\n    }\n    owned_ = nullptr;\n  }\n}\n\nMonitorLock::~MonitorLock() noexcept {\n  reset();\n}\n\nMonitorLock::MonitorLock(MonitorLock&& other) noexcept\n    : owned_(other.owned_)\n{\n  other.owned_ = nullptr;\n}\n\nMonitorLock& MonitorLock::operator=(MonitorLock&& other) noexcept {\n  reset();\n  owned_ = other.owned_;\n  other.owned_ = nullptr;\n  return *this;\n}\n\ninline MonitorLock JObject::lock() const noexcept {\n  return MonitorLock(this_);\n}\n\ninline jobject JObject::self() const noexcept {\n  return this_;\n}\n\ninline void swap(JObject& a, JObject& b) noexcept {\n  using std::swap;\n  swap(a.this_, b.this_);\n}\n\n// JavaClass ///////////////////////////////////////////////////////////////////////////////////////\n\nnamespace detail {\ntemplate<typename JC, typename... Args>\nstatic local_ref<JC> newInstance(Args... args) {\n  static auto cls = JC::javaClassStatic();\n  static auto constructor = cls->template getConstructor<typename JC::javaobject(Args...)>();\n  return cls->newObject(constructor, args...);\n}\n}\n\n\ntemplate <typename T, typename B, typename J>\nauto JavaClass<T, B, J>::self() const noexcept -> javaobject {\n  return static_cast<javaobject>(JObject::self());\n}\n\n// jclass //////////////////////////////////////////////////////////////////////////////////////////\n\nnamespace detail {\n\n// This is not a real type.  It is used so people won't accidentally\n// use a void* to initialize a NativeMethod.\nstruct NativeMethodWrapper;\n\n}\n\nstruct NativeMethod {\n  const char* name;\n  std::string descriptor;\n  detail::NativeMethodWrapper* wrapper;\n};\n\ninline local_ref<JClass> JClass::getSuperclass() const noexcept {\n  return adopt_local(internal::getEnv()->GetSuperclass(self()));\n}\n\ninline void JClass::registerNatives(std::initializer_list<NativeMethod> methods) {\n  const auto env = internal::getEnv();\n\n  JNINativeMethod jnimethods[methods.size()];\n  size_t i = 0;\n  for (auto it = methods.begin(); it < methods.end(); ++it, ++i) {\n    jnimethods[i].name = it->name;\n    jnimethods[i].signature = it->descriptor.c_str();\n    jnimethods[i].fnPtr = reinterpret_cast<void*>(it->wrapper);\n  }\n\n  auto result = env->RegisterNatives(self(), jnimethods, methods.size());\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(result != JNI_OK);\n}\n\ninline bool JClass::isAssignableFrom(alias_ref<JClass> other) const noexcept {\n  const auto env = internal::getEnv();\n  // Ths method has behavior compatible with the\n  // java.lang.Class#isAssignableFrom method.  The order of the\n  // arguments to the JNI IsAssignableFrom C function is \"opposite\"\n  // from what some might expect, which makes this code look a little\n  // odd, but it is correct.\n  const auto result = env->IsAssignableFrom(other.get(), self());\n  return result;\n}\n\ntemplate<typename F>\ninline JConstructor<F> JClass::getConstructor() const {\n  return getConstructor<F>(jmethod_traits_from_cxx<F>::constructor_descriptor().c_str());\n}\n\ntemplate<typename F>\ninline JConstructor<F> JClass::getConstructor(const char* descriptor) const {\n  constexpr auto constructor_method_name = \"<init>\";\n  return getMethod<F>(constructor_method_name, descriptor);\n}\n\ntemplate<typename F>\ninline JMethod<F> JClass::getMethod(const char* name) const {\n  return getMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());\n}\n\ntemplate<typename F>\ninline JMethod<F> JClass::getMethod(\n    const char* name,\n    const char* descriptor) const {\n  const auto env = internal::getEnv();\n  const auto method = env->GetMethodID(self(), name, descriptor);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);\n  return JMethod<F>{method};\n}\n\ntemplate<typename F>\ninline JStaticMethod<F> JClass::getStaticMethod(const char* name) const {\n  return getStaticMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());\n}\n\ntemplate<typename F>\ninline JStaticMethod<F> JClass::getStaticMethod(\n    const char* name,\n    const char* descriptor) const {\n  const auto env = internal::getEnv();\n  const auto method = env->GetStaticMethodID(self(), name, descriptor);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);\n  return JStaticMethod<F>{method};\n}\n\ntemplate<typename F>\ninline JNonvirtualMethod<F> JClass::getNonvirtualMethod(const char* name) const {\n  return getNonvirtualMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());\n}\n\ntemplate<typename F>\ninline JNonvirtualMethod<F> JClass::getNonvirtualMethod(\n    const char* name,\n    const char* descriptor) const {\n  const auto env = internal::getEnv();\n  const auto method = env->GetMethodID(self(), name, descriptor);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);\n  return JNonvirtualMethod<F>{method};\n}\n\ntemplate<typename T>\ninline JField<enable_if_t<IsJniScalar<T>(), T>>\nJClass::getField(const char* name) const {\n  return getField<T>(name, jtype_traits<T>::descriptor().c_str());\n}\n\ntemplate<typename T>\ninline JField<enable_if_t<IsJniScalar<T>(), T>> JClass::getField(\n    const char* name,\n    const char* descriptor) const {\n  const auto env = internal::getEnv();\n  auto field = env->GetFieldID(self(), name, descriptor);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!field);\n  return JField<T>{field};\n}\n\ntemplate<typename T>\ninline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JClass::getStaticField(\n    const char* name) const {\n  return getStaticField<T>(name, jtype_traits<T>::descriptor().c_str());\n}\n\ntemplate<typename T>\ninline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JClass::getStaticField(\n    const char* name,\n    const char* descriptor) const {\n  const auto env = internal::getEnv();\n  auto field = env->GetStaticFieldID(self(), name, descriptor);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!field);\n  return JStaticField<T>{field};\n}\n\ntemplate<typename T>\ninline T JClass::getStaticFieldValue(JStaticField<T> field) const noexcept {\n  return field.get(self());\n}\n\ntemplate<typename T>\ninline local_ref<T*> JClass::getStaticFieldValue(JStaticField<T*> field) noexcept {\n  return adopt_local(field.get(self()));\n}\n\ntemplate<typename T>\ninline void JClass::setStaticFieldValue(JStaticField<T> field, T value) noexcept {\n  field.set(self(), value);\n}\n\ntemplate<typename R, typename... Args>\ninline local_ref<R> JClass::newObject(\n    JConstructor<R(Args...)> constructor,\n    Args... args) const {\n  const auto env = internal::getEnv();\n  auto object = env->NewObject(self(), constructor.getId(),\n      detail::callToJni(\n        detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!object);\n  return adopt_local(static_cast<R>(object));\n}\n\ninline jclass JClass::self() const noexcept {\n  return static_cast<jclass>(JObject::self());\n}\n\ninline void registerNatives(const char* name, std::initializer_list<NativeMethod> methods) {\n  findClassLocal(name)->registerNatives(methods);\n}\n\n\n// jstring /////////////////////////////////////////////////////////////////////////////////////////\n\ninline local_ref<JString> make_jstring(const std::string& modifiedUtf8) {\n  return make_jstring(modifiedUtf8.c_str());\n}\n\nnamespace detail {\n// convert to std::string from jstring\ntemplate <>\nstruct Convert<std::string> {\n  typedef jstring jniType;\n  static std::string fromJni(jniType t) {\n    return wrap_alias(t)->toStdString();\n  }\n  static jniType toJniRet(const std::string& t) {\n    return make_jstring(t).release();\n  }\n  static local_ref<JString> toCall(const std::string& t) {\n    return make_jstring(t);\n  }\n};\n\n// convert return from const char*\ntemplate <>\nstruct Convert<const char*> {\n  typedef jstring jniType;\n  // no automatic synthesis of const char*.  (It can't be freed.)\n  static jniType toJniRet(const char* t) {\n    return make_jstring(t).release();\n  }\n  static local_ref<JString> toCall(const char* t) {\n    return make_jstring(t);\n  }\n};\n}\n\n// jtypeArray //////////////////////////////////////////////////////////////////////////////////////\n\nnamespace detail {\ninline size_t JArray::size() const noexcept {\n  const auto env = internal::getEnv();\n  return env->GetArrayLength(self());\n}\n}\n\nnamespace detail {\ntemplate<typename Target>\ninline ElementProxy<Target>::ElementProxy(\n    Target* target,\n    size_t idx)\n    : target_{target}, idx_{idx} {}\n\ntemplate<typename Target>\ninline ElementProxy<Target>& ElementProxy<Target>::operator=(const T& o) {\n  target_->setElement(idx_, o);\n  return *this;\n}\n\ntemplate<typename Target>\ninline ElementProxy<Target>& ElementProxy<Target>::operator=(alias_ref<T>& o) {\n  target_->setElement(idx_, o.get());\n  return *this;\n}\n\ntemplate<typename Target>\ninline ElementProxy<Target>& ElementProxy<Target>::operator=(alias_ref<T>&& o) {\n  target_->setElement(idx_, o.get());\n  return *this;\n}\n\ntemplate<typename Target>\ninline ElementProxy<Target>& ElementProxy<Target>::operator=(const ElementProxy<Target>& o) {\n  auto src = o.target_->getElement(o.idx_);\n  target_->setElement(idx_, src.get());\n  return *this;\n}\n\ntemplate<typename Target>\ninline ElementProxy<Target>::ElementProxy::operator const local_ref<T> () const {\n  return target_->getElement(idx_);\n}\n\ntemplate<typename Target>\ninline ElementProxy<Target>::ElementProxy::operator local_ref<T> () {\n  return target_->getElement(idx_);\n}\n}\n\ntemplate <typename T>\nstd::string JArrayClass<T>::get_instantiated_java_descriptor() {\n  return \"[\" + jtype_traits<T>::descriptor();\n};\n\ntemplate <typename T>\nstd::string JArrayClass<T>::get_instantiated_base_name() {\n  return get_instantiated_java_descriptor();\n};\n\ntemplate<typename T>\nauto JArrayClass<T>::newArray(size_t size) -> local_ref<javaobject> {\n  static auto elementClass = findClassStatic(jtype_traits<T>::base_name().c_str());\n  const auto env = internal::getEnv();\n  auto rawArray = env->NewObjectArray(size, elementClass.get(), nullptr);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray);\n  return adopt_local(static_cast<javaobject>(rawArray));\n}\n\ntemplate<typename T>\ninline void JArrayClass<T>::setElement(size_t idx, const T& value) {\n  const auto env = internal::getEnv();\n  env->SetObjectArrayElement(this->self(), idx, value);\n}\n\ntemplate<typename T>\ninline local_ref<T> JArrayClass<T>::getElement(size_t idx) {\n  const auto env = internal::getEnv();\n  auto rawElement = env->GetObjectArrayElement(this->self(), idx);\n  return adopt_local(static_cast<T>(rawElement));\n}\n\ntemplate<typename T>\ninline detail::ElementProxy<JArrayClass<T>> JArrayClass<T>::operator[](size_t index) {\n  return detail::ElementProxy<JArrayClass<T>>(this, index);\n}\n\n// jarray /////////////////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename JArrayType>\nauto JPrimitiveArray<JArrayType>::getRegion(jsize start, jsize length)\n    -> std::unique_ptr<T[]> {\n  using T = typename jtype_traits<JArrayType>::entry_type;\n  auto buf = std::unique_ptr<T[]>{new T[length]};\n  getRegion(start, length, buf.get());\n  return buf;\n}\n\ntemplate <typename JArrayType>\nstd::string JPrimitiveArray<JArrayType>::get_instantiated_java_descriptor() {\n  return jtype_traits<JArrayType>::descriptor();\n}\ntemplate <typename JArrayType>\nstd::string JPrimitiveArray<JArrayType>::get_instantiated_base_name() {\n  return JPrimitiveArray::get_instantiated_java_descriptor();\n}\n\ntemplate <typename JArrayType>\nauto JPrimitiveArray<JArrayType>::pin() -> PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> {\n  return PinnedPrimitiveArray<T, PinnedArrayAlloc<T>>{this->self(), 0, 0};\n}\n\ntemplate <typename JArrayType>\nauto JPrimitiveArray<JArrayType>::pinRegion(jsize start, jsize length)\n    -> PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> {\n  return PinnedPrimitiveArray<T, PinnedRegionAlloc<T>>{this->self(), start, length};\n}\n\ntemplate <typename JArrayType>\nauto JPrimitiveArray<JArrayType>::pinCritical()\n    -> PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> {\n  return PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>>{this->self(), 0, 0};\n}\n\ntemplate <typename T>\nclass PinnedArrayAlloc {\n public:\n  static void allocate(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      jsize start,\n      jsize length,\n      T** elements,\n      size_t* size,\n      jboolean* isCopy) {\n    (void) start;\n    (void) length;\n    *elements = array->getElements(isCopy);\n    *size = array->size();\n  }\n  static void release(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      T* elements,\n      jint start,\n      jint size,\n      jint mode) {\n    (void) start;\n    (void) size;\n    array->releaseElements(elements, mode);\n  }\n};\n\ntemplate <typename T>\nclass PinnedCriticalAlloc {\n public:\n  static void allocate(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      jsize start,\n      jsize length,\n      T** elements,\n      size_t* size,\n      jboolean* isCopy) {\n    const auto env = internal::getEnv();\n    *elements = static_cast<T*>(env->GetPrimitiveArrayCritical(array.get(), isCopy));\n    FACEBOOK_JNI_THROW_EXCEPTION_IF(!elements);\n    *size = array->size();\n  }\n  static void release(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      T* elements,\n      jint start,\n      jint size,\n      jint mode) {\n    const auto env = internal::getEnv();\n    env->ReleasePrimitiveArrayCritical(array.get(), elements, mode);\n  }\n};\n\ntemplate <typename T>\nclass PinnedRegionAlloc {\n public:\n  static void allocate(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      jsize start,\n      jsize length,\n      T** elements,\n      size_t* size,\n      jboolean* isCopy) {\n    auto buf = array->getRegion(start, length);\n    FACEBOOK_JNI_THROW_EXCEPTION_IF(!buf);\n    *elements = buf.release();\n    *size = length;\n    *isCopy = true;\n  }\n  static void release(\n      alias_ref<typename jtype_traits<T>::array_type> array,\n      T* elements,\n      jint start,\n      jint size,\n      jint mode) {\n    std::unique_ptr<T[]> holder;\n    if (mode == 0 || mode == JNI_ABORT) {\n      holder.reset(elements);\n    }\n    if (mode == 0 || mode == JNI_COMMIT) {\n      array->setRegion(start, size, elements);\n    }\n  }\n};\n\n// PinnedPrimitiveArray ///////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T, typename Alloc>\nPinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(PinnedPrimitiveArray&& o) {\n  *this = std::move(o);\n}\n\ntemplate<typename T, typename Alloc>\nPinnedPrimitiveArray<T, Alloc>&\nPinnedPrimitiveArray<T, Alloc>::operator=(PinnedPrimitiveArray&& o) {\n  if (array_) {\n    release();\n  }\n  array_ = std::move(o.array_);\n  elements_ = o.elements_;\n  isCopy_ = o.isCopy_;\n  size_ = o.size_;\n  start_ = o.start_;\n  o.clear();\n  return *this;\n}\n\ntemplate<typename T, typename Alloc>\nT* PinnedPrimitiveArray<T, Alloc>::get() {\n  return elements_;\n}\n\ntemplate<typename T, typename Alloc>\ninline void PinnedPrimitiveArray<T, Alloc>::release() {\n  releaseImpl(0);\n  clear();\n}\n\ntemplate<typename T, typename Alloc>\ninline void PinnedPrimitiveArray<T, Alloc>::commit() {\n  releaseImpl(JNI_COMMIT);\n}\n\ntemplate<typename T, typename Alloc>\ninline void PinnedPrimitiveArray<T, Alloc>::abort() {\n  releaseImpl(JNI_ABORT);\n  clear();\n}\n\ntemplate <typename T, typename Alloc>\ninline void PinnedPrimitiveArray<T, Alloc>::releaseImpl(jint mode) {\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(array_.get() == nullptr);\n  Alloc::release(array_, elements_, start_, size_, mode);\n}\n\ntemplate<typename T, typename Alloc>\ninline void PinnedPrimitiveArray<T, Alloc>::clear() noexcept {\n  array_ = nullptr;\n  elements_ = nullptr;\n  isCopy_ = false;\n  start_ = 0;\n  size_ = 0;\n}\n\ntemplate<typename T, typename Alloc>\ninline T& PinnedPrimitiveArray<T, Alloc>::operator[](size_t index) {\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(elements_ == nullptr);\n  return elements_[index];\n}\n\ntemplate<typename T, typename Alloc>\ninline bool PinnedPrimitiveArray<T, Alloc>::isCopy() const noexcept {\n  return isCopy_ == JNI_TRUE;\n}\n\ntemplate<typename T, typename Alloc>\ninline size_t PinnedPrimitiveArray<T, Alloc>::size() const noexcept {\n  return size_;\n}\n\ntemplate<typename T, typename Alloc>\ninline PinnedPrimitiveArray<T, Alloc>::~PinnedPrimitiveArray() noexcept {\n  if (elements_) {\n    release();\n  }\n}\n\ntemplate<typename T, typename Alloc>\ninline PinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(alias_ref<typename jtype_traits<T>::array_type> array, jint start, jint length) {\n  array_ = array;\n  start_ = start;\n  Alloc::allocate(array, start, length, &elements_, &size_, &isCopy_);\n}\n\ntemplate<typename T, typename Base, typename JType>\ninline alias_ref<JClass> JavaClass<T, Base, JType>::javaClassStatic() {\n  static auto cls = findClassStatic(jtype_traits<typename T::javaobject>::base_name().c_str());\n  return cls;\n}\n\ntemplate<typename T, typename Base, typename JType>\ninline local_ref<JClass> JavaClass<T, Base, JType>::javaClassLocal() {\n  std::string className(jtype_traits<typename T::javaobject>::base_name().c_str());\n  return findClassLocal(className.c_str());\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/CoreClasses.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n/** @file CoreClasses.h\n *\n * In CoreClasses.h wrappers for the core classes (jobject, jclass, and jstring) is defined\n * to provide access to corresponding JNI functions + some conveniance.\n */\n\n#include \"References-forward.h\"\n#include \"Meta-forward.h\"\n#include \"TypeTraits.h\"\n\n#include <memory>\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace jni {\n\nclass JClass;\nclass JObject;\n\n/// Lookup a class by name. Note this functions returns an alias_ref that\n/// points to a leaked global reference.  This is appropriate for classes\n/// that are never unloaded (which is any class in an Android app and most\n/// Java programs).\n///\n/// The most common use case for this is storing the result\n/// in a \"static auto\" variable, or a static global.\n///\n/// @return Returns a leaked global reference to the class\nFBEXPORT alias_ref<JClass> findClassStatic(const char* name);\n\n/// Lookup a class by name. Note this functions returns a local reference,\n/// which means that it must not be stored in a static variable.\n///\n/// The most common use case for this is one-time initialization\n/// (like caching method ids).\n///\n/// @return Returns a global reference to the class\nFBEXPORT local_ref<JClass> findClassLocal(const char* name);\n\n/// Check to see if two references refer to the same object. Comparison with nullptr\n/// returns true if and only if compared to another nullptr. A weak reference that\n/// refers to a reclaimed object count as nullptr.\nFBEXPORT bool isSameObject(alias_ref<JObject> lhs, alias_ref<JObject> rhs) noexcept;\n\n// Together, these classes allow convenient use of any class with the fbjni\n// helpers.  To use:\n//\n// struct MyClass : public JavaClass<MyClass> {\n//   constexpr static auto kJavaDescriptor = \"Lcom/example/package/MyClass;\";\n// };\n//\n// Then, an alias_ref<MyClass::javaobject> will be backed by an instance of\n// MyClass. JavaClass provides a convenient way to add functionality to these\n// smart references.\n//\n// For example:\n//\n// struct MyClass : public JavaClass<MyClass> {\n//   constexpr static auto kJavaDescriptor = \"Lcom/example/package/MyClass;\";\n//\n//   void foo() {\n//     static auto method = javaClassStatic()->getMethod<void()>(\"foo\");\n//     method(self());\n//   }\n//\n//   static local_ref<javaobject> create(int i) {\n//     return newInstance(i);\n//   }\n// };\n//\n// auto obj = MyClass::create(10);\n// obj->foo();\n//\n// While users of a JavaClass-type can lookup methods and fields through the\n// underlying JClass, those calls can only be checked at runtime. It is recommended\n// that the JavaClass-type instead explicitly expose it's methods as in the example\n// above.\n\nnamespace detail {\ntemplate<typename JC, typename... Args>\nstatic local_ref<JC> newInstance(Args... args);\n}\n\nclass MonitorLock;\n\nclass FBEXPORT JObject : detail::JObjectBase {\npublic:\n  static constexpr auto kJavaDescriptor = \"Ljava/lang/Object;\";\n\n  static constexpr const char* get_instantiated_java_descriptor() { return nullptr; }\n  static constexpr const char* get_instantiated_base_name() { return nullptr; }\n\n  /// Get a @ref local_ref of the object's class\n  local_ref<JClass> getClass() const noexcept;\n\n  /// Checks if the object is an instance of a class\n  bool isInstanceOf(alias_ref<JClass> cls) const noexcept;\n\n  /// Get the primitive value of a field\n  template<typename T>\n  T getFieldValue(JField<T> field) const noexcept;\n\n  /// Get and wrap the value of a field in a @ref local_ref\n  template<typename T>\n  local_ref<T*> getFieldValue(JField<T*> field) const noexcept;\n\n  /// Set the value of field. Any Java type is accepted, including the primitive types\n  /// and raw reference types.\n  template<typename T>\n  void setFieldValue(JField<T> field, T value) noexcept;\n\n  /// Convenience method to create a std::string representing the object\n  std::string toString() const;\n\n  // Take this object's monitor lock\n  MonitorLock lock() const noexcept;\n\n  typedef _jobject _javaobject;\n  typedef _javaobject* javaobject;\n\nprotected:\n  jobject self() const noexcept;\nprivate:\n  friend void swap(JObject& a, JObject& b) noexcept;\n  template<typename>\n  friend struct detail::ReprAccess;\n  template<typename, typename, typename>\n  friend class JavaClass;\n\n  template <typename, typename>\n  friend class JObjectWrapper;\n};\n\n// This is only to maintain backwards compatibility with things that are\n// already providing a specialization of JObjectWrapper. Any such instances\n// should be updated to use a JavaClass.\ntemplate<>\nclass JObjectWrapper<jobject> : public JObject {\n};\n\n\nnamespace detail {\ntemplate <typename, typename Base, typename JType>\nstruct JTypeFor {\n  static_assert(\n      std::is_base_of<\n        std::remove_pointer<jobject>::type,\n        typename std::remove_pointer<JType>::type\n      >::value, \"\");\n  using _javaobject = typename std::remove_pointer<JType>::type;\n  using javaobject = JType;\n};\n\ntemplate <typename T, typename Base>\nstruct JTypeFor<T, Base, void> {\n  // JNI pattern for jobject assignable pointer\n  struct _javaobject :  Base::_javaobject {\n    // This allows us to map back to the defining type (in ReprType, for\n    // example).\n    typedef T JniRefRepr;\n  };\n  using javaobject = _javaobject*;\n};\n}\n\n// JavaClass provides a method to inform fbjni about user-defined Java types.\n// Given a class:\n// struct Foo : JavaClass<Foo> {\n//   static constexpr auto kJavaDescriptor = \"Lcom/example/package/Foo;\";\n// };\n// fbjni can determine the java type/method signatures for Foo::javaobject and\n// smart refs (like alias_ref<Foo::javaobject>) will hold an instance of Foo\n// and provide access to it through the -> and * operators.\n//\n// The \"Base\" template argument can be used to specify the JavaClass superclass\n// of this type (for instance, JString's Base is JObject).\n//\n// The \"JType\" template argument is used to provide a jni type (like jstring,\n// jthrowable) to be used as javaobject. This should only be necessary for\n// built-in jni types and not user-defined ones.\ntemplate <typename T, typename Base = JObject, typename JType = void>\nclass FBEXPORT JavaClass : public Base {\n  using JObjType = typename detail::JTypeFor<T, Base, JType>;\npublic:\n  using _javaobject = typename JObjType::_javaobject;\n  using javaobject = typename JObjType::javaobject;\n\n  using JavaBase = JavaClass;\n\n  static alias_ref<JClass> javaClassStatic();\n  static local_ref<JClass> javaClassLocal();\nprotected:\n  /// Allocates a new object and invokes the specified constructor\n  /// Like JClass's getConstructor, this function can only check at runtime if\n  /// the class actually has a constructor that accepts the corresponding types.\n  /// While a JavaClass-type can expose this function directly, it is recommended\n  /// to instead to use this to explicitly only expose those constructors that\n  /// the Java class actually has (i.e. with static create() functions).\n  template<typename... Args>\n  static local_ref<T> newInstance(Args... args) {\n    return detail::newInstance<T>(args...);\n  }\n\n  javaobject self() const noexcept;\n};\n\n/// Wrapper to provide functionality to jclass references\nstruct NativeMethod;\n\nclass FBEXPORT JClass : public JavaClass<JClass, JObject, jclass> {\n public:\n  /// Java type descriptor\n  static constexpr const char* kJavaDescriptor = \"Ljava/lang/Class;\";\n\n  /// Get a @local_ref to the super class of this class\n  local_ref<JClass> getSuperclass() const noexcept;\n\n  /// Register native methods for the class.  Usage looks like this:\n  ///\n  /// classRef->registerNatives({\n  ///     makeNativeMethod(\"nativeMethodWithAutomaticDescriptor\",\n  ///                      methodWithAutomaticDescriptor),\n  ///     makeNativeMethod(\"nativeMethodWithExplicitDescriptor\",\n  ///                      \"(Lcom/facebook/example/MyClass;)V\",\n  ///                      methodWithExplicitDescriptor),\n  ///  });\n  ///\n  /// By default, C++ exceptions raised will be converted to Java exceptions.\n  /// To avoid this and get the \"standard\" JNI behavior of a crash when a C++\n  /// exception is crashing out of the JNI method, declare the method noexcept.\n  void registerNatives(std::initializer_list<NativeMethod> methods);\n\n  /// Check to see if the class is assignable from another class\n  /// @pre cls != nullptr\n  bool isAssignableFrom(alias_ref<JClass> cls) const noexcept;\n\n  /// Convenience method to lookup the constructor with descriptor as specified by the\n  /// type arguments\n  template<typename F>\n  JConstructor<F> getConstructor() const;\n\n  /// Convenience method to lookup the constructor with specified descriptor\n  template<typename F>\n  JConstructor<F> getConstructor(const char* descriptor) const;\n\n  /// Look up the method with given name and descriptor as specified with the type arguments\n  template<typename F>\n  JMethod<F> getMethod(const char* name) const;\n\n  /// Look up the method with given name and descriptor\n  template<typename F>\n  JMethod<F> getMethod(const char* name, const char* descriptor) const;\n\n  /// Lookup the field with the given name and deduced descriptor\n  template<typename T>\n  JField<enable_if_t<IsJniScalar<T>(), T>> getField(const char* name) const;\n\n  /// Lookup the field with the given name and descriptor\n  template<typename T>\n  JField<enable_if_t<IsJniScalar<T>(), T>> getField(const char* name, const char* descriptor) const;\n\n  /// Lookup the static field with the given name and deduced descriptor\n  template<typename T>\n  JStaticField<enable_if_t<IsJniScalar<T>(), T>> getStaticField(const char* name) const;\n\n  /// Lookup the static field with the given name and descriptor\n  template<typename T>\n  JStaticField<enable_if_t<IsJniScalar<T>(), T>> getStaticField(\n      const char* name,\n      const char* descriptor) const;\n\n  /// Get the primitive value of a static field\n  template<typename T>\n  T getStaticFieldValue(JStaticField<T> field) const noexcept;\n\n  /// Get and wrap the value of a field in a @ref local_ref\n  template<typename T>\n  local_ref<T*> getStaticFieldValue(JStaticField<T*> field) noexcept;\n\n  /// Set the value of field. Any Java type is accepted, including the primitive types\n  /// and raw reference types.\n  template<typename T>\n  void setStaticFieldValue(JStaticField<T> field, T value) noexcept;\n\n  /// Allocates a new object and invokes the specified constructor\n  template<typename R, typename... Args>\n  local_ref<R> newObject(JConstructor<R(Args...)> constructor, Args... args) const;\n\n  /// Look up the static method with given name and descriptor as specified with the type arguments\n  template<typename F>\n  JStaticMethod<F> getStaticMethod(const char* name) const;\n\n  /// Look up the static method with given name and descriptor\n  template<typename F>\n  JStaticMethod<F> getStaticMethod(const char* name, const char* descriptor) const;\n\n  /// Look up the non virtual method with given name and descriptor as specified with the\n  /// type arguments\n  template<typename F>\n  JNonvirtualMethod<F> getNonvirtualMethod(const char* name) const;\n\n  /// Look up the non virtual method with given name and descriptor\n  template<typename F>\n  JNonvirtualMethod<F> getNonvirtualMethod(const char* name, const char* descriptor) const;\n\nprivate:\n  jclass self() const noexcept;\n};\n\n// Convenience method to register methods on a class without holding\n// onto the class object.\nvoid registerNatives(const char* name, std::initializer_list<NativeMethod> methods);\n\n/// Wrapper to provide functionality to jstring references\nclass FBEXPORT JString : public JavaClass<JString, JObject, jstring> {\n public:\n  /// Java type descriptor\n  static constexpr const char* kJavaDescriptor = \"Ljava/lang/String;\";\n\n  /// Convenience method to convert a jstring object to a std::string\n  std::string toStdString() const;\n};\n\n/// Convenience functions to convert a std::string or const char* into a @ref local_ref to a\n/// jstring\nFBEXPORT local_ref<JString> make_jstring(const char* modifiedUtf8);\nFBEXPORT local_ref<JString> make_jstring(const std::string& modifiedUtf8);\n\nnamespace detail {\ntemplate<typename Target>\nclass ElementProxy {\n private:\n  Target* target_;\n  size_t idx_;\n\n public:\n  using T = typename Target::javaentry;\n  ElementProxy(Target* target, size_t idx);\n\n  ElementProxy& operator=(const T& o);\n\n  ElementProxy& operator=(alias_ref<T>& o);\n\n  ElementProxy& operator=(alias_ref<T>&& o);\n\n  ElementProxy& operator=(const ElementProxy& o);\n\n  operator const local_ref<T> () const;\n\n  operator local_ref<T> ();\n};\n}\n\nnamespace detail {\nclass FBEXPORT JArray : public JavaClass<JArray, JObject, jarray> {\n public:\n  // This cannot be used in a scope that derives a descriptor (like in a method\n  // signature). Use a more derived type instead (like JArrayInt or\n  // JArrayClass<T>).\n  static constexpr const char* kJavaDescriptor = nullptr;\n  size_t size() const noexcept;\n};\n\n// This is used so that the JArrayClass<T> javaobject extends jni's\n// jobjectArray. This class should not be used directly. A general Object[]\n// should use JArrayClass<jobject>.\nclass FBEXPORT JTypeArray : public JavaClass<JTypeArray, JArray, jobjectArray> {\n  // This cannot be used in a scope that derives a descriptor (like in a method\n  // signature).\n  static constexpr const char* kJavaDescriptor = nullptr;\n};\n}\n\ntemplate<typename T>\nclass JArrayClass : public JavaClass<JArrayClass<T>, detail::JTypeArray> {\n public:\n  static_assert(is_plain_jni_reference<T>(), \"\");\n  // javaentry is the jni type of an entry in the array (i.e. jint).\n  using javaentry = T;\n  // javaobject is the jni type of the array.\n  using javaobject = typename JavaClass<JArrayClass<T>, detail::JTypeArray>::javaobject;\n  static constexpr const char* kJavaDescriptor = nullptr;\n  static std::string get_instantiated_java_descriptor();\n  static std::string get_instantiated_base_name();\n\n  /// Allocate a new array from Java heap, for passing as a JNI parameter or return value.\n  /// NOTE: if using as a return value, you want to call release() instead of get() on the\n  /// smart pointer.\n  static local_ref<javaobject> newArray(size_t count);\n\n  /// Assign an object to the array.\n  /// Typically you will use the shorthand (*ref)[idx]=value;\n  void setElement(size_t idx, const T& value);\n\n  /// Read an object from the array.\n  /// Typically you will use the shorthand\n  ///   T value = (*ref)[idx];\n  /// If you use auto, you'll get an ElementProxy, which may need to be cast.\n  local_ref<T> getElement(size_t idx);\n\n  /// EXPERIMENTAL SUBSCRIPT SUPPORT\n  /// This implementation of [] returns a proxy object which then has a bunch of specializations\n  /// (adopt_local free function, operator= and casting overloads on the ElementProxy) that can\n  /// make code look like it is dealing with a T rather than an obvious proxy. In particular, the\n  /// proxy in this iteration does not read a value and therefore does not create a LocalRef\n  /// until one of these other operators is used. There are certainly holes that you may find\n  /// by using idioms that haven't been tried yet. Consider yourself warned. On the other hand,\n  /// it does make for some idiomatic assignment code; see TestBuildStringArray in fbjni_tests\n  /// for some examples.\n  detail::ElementProxy<JArrayClass> operator[](size_t idx);\n};\n\ntemplate <typename T>\nusing jtypeArray = typename JArrayClass<T>::javaobject;\n\ntemplate<typename T>\nlocal_ref<typename JArrayClass<T>::javaobject> adopt_local_array(jobjectArray ref) {\n  return adopt_local(static_cast<typename JArrayClass<T>::javaobject>(ref));\n}\n\ntemplate<typename Target>\nlocal_ref<typename Target::javaentry> adopt_local(detail::ElementProxy<Target> elementProxy) {\n  return static_cast<local_ref<typename Target::javaentry>>(elementProxy);\n}\n\ntemplate <typename T, typename PinAlloc>\nclass PinnedPrimitiveArray;\n\ntemplate <typename T> class PinnedArrayAlloc;\ntemplate <typename T> class PinnedRegionAlloc;\ntemplate <typename T> class PinnedCriticalAlloc;\n\n/// Wrapper to provide functionality to jarray references.\n/// This is an empty holder by itself. Construct a PinnedPrimitiveArray to actually interact with\n/// the elements of the array.\ntemplate <typename JArrayType>\nclass FBEXPORT JPrimitiveArray :\n    public JavaClass<JPrimitiveArray<JArrayType>, detail::JArray, JArrayType> {\n  static_assert(is_jni_primitive_array<JArrayType>(), \"\");\n public:\n  static constexpr const char* kJavaDescriptor = nullptr;\n  static std::string get_instantiated_java_descriptor();\n  static std::string get_instantiated_base_name();\n\n  using T = typename jtype_traits<JArrayType>::entry_type;\n\n  static local_ref<JArrayType> newArray(size_t count);\n\n  void getRegion(jsize start, jsize length, T* buf);\n  std::unique_ptr<T[]> getRegion(jsize start, jsize length);\n  void setRegion(jsize start, jsize length, const T* buf);\n\n  /// Returns a view of the underlying array. This will either be a \"pinned\"\n  /// version of the array (in which case changes to one immediately affect the\n  /// other) or a copy of the array (in which cases changes to the view will take\n  /// affect when destroyed or on calls to release()/commit()).\n  PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> pin();\n\n  /// Returns a view of part of the underlying array. A pinned region is always\n  /// backed by a copy of the region.\n  PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> pinRegion(jsize start, jsize length);\n\n  /// Returns a view of the underlying array like pin(). However, while the pin\n  /// is held, the code is considered within a \"critical region\". In a critical\n  /// region, native code must not call JNI functions or make any calls that may\n  /// block on other Java threads. These restrictions make it more likely that\n  /// the view will be \"pinned\" rather than copied (for example, the VM may\n  /// suspend garbage collection within a critical region).\n  PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> pinCritical();\n\nprivate:\n  friend class PinnedArrayAlloc<T>;\n  T* getElements(jboolean* isCopy);\n  void releaseElements(T* elements, jint mode);\n};\n\nFBEXPORT local_ref<jbooleanArray> make_boolean_array(jsize size);\nFBEXPORT local_ref<jbyteArray> make_byte_array(jsize size);\nFBEXPORT local_ref<jcharArray> make_char_array(jsize size);\nFBEXPORT local_ref<jshortArray> make_short_array(jsize size);\nFBEXPORT local_ref<jintArray> make_int_array(jsize size);\nFBEXPORT local_ref<jlongArray> make_long_array(jsize size);\nFBEXPORT local_ref<jfloatArray> make_float_array(jsize size);\nFBEXPORT local_ref<jdoubleArray> make_double_array(jsize size);\n\nusing JArrayBoolean = JPrimitiveArray<jbooleanArray>;\nusing JArrayByte = JPrimitiveArray<jbyteArray>;\nusing JArrayChar = JPrimitiveArray<jcharArray>;\nusing JArrayShort = JPrimitiveArray<jshortArray>;\nusing JArrayInt = JPrimitiveArray<jintArray>;\nusing JArrayLong = JPrimitiveArray<jlongArray>;\nusing JArrayFloat = JPrimitiveArray<jfloatArray>;\nusing JArrayDouble = JPrimitiveArray<jdoubleArray>;\n\n/// RAII class for pinned primitive arrays\n/// This currently only supports read/write access to existing java arrays. You can't create a\n/// primitive array this way yet. This class also pins the entire array into memory during the\n/// lifetime of the PinnedPrimitiveArray. If you need to unpin the array manually, call the\n/// release() or abort() functions. During a long-running block of code, you\n/// should unpin the array as soon as you're done with it, to avoid holding up\n/// the Java garbage collector.\ntemplate <typename T, typename PinAlloc>\nclass PinnedPrimitiveArray {\n  public:\n   static_assert(is_jni_primitive<T>::value,\n       \"PinnedPrimitiveArray requires primitive jni type.\");\n\n   using ArrayType = typename jtype_traits<T>::array_type;\n\n   PinnedPrimitiveArray(PinnedPrimitiveArray&&);\n   PinnedPrimitiveArray(const PinnedPrimitiveArray&) = delete;\n   ~PinnedPrimitiveArray() noexcept;\n\n   PinnedPrimitiveArray& operator=(PinnedPrimitiveArray&&);\n   PinnedPrimitiveArray& operator=(const PinnedPrimitiveArray&) = delete;\n\n   T* get();\n   void release();\n   /// Unpins the array. If the array is a copy, pending changes are discarded.\n   void abort();\n   /// If the array is a copy, copies pending changes to the underlying java array.\n   void commit();\n\n   bool isCopy() const noexcept;\n\n   const T& operator[](size_t index) const;\n   T& operator[](size_t index);\n   size_t size() const noexcept;\n\n  private:\n   alias_ref<ArrayType> array_;\n   size_t start_;\n   T* elements_;\n   jboolean isCopy_;\n   size_t size_;\n\n   void allocate(alias_ref<ArrayType>, jint start, jint length);\n   void releaseImpl(jint mode);\n   void clear() noexcept;\n\n   PinnedPrimitiveArray(alias_ref<ArrayType>, jint start, jint length);\n\n   friend class JPrimitiveArray<typename jtype_traits<T>::array_type>;\n};\n\nstruct FBEXPORT JStackTraceElement : JavaClass<JStackTraceElement> {\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/StackTraceElement;\";\n\n  static local_ref<javaobject> create(const std::string& declaringClass, const std::string& methodName, const std::string& file, int line);\n\n  std::string getClassName() const;\n  std::string getMethodName() const;\n  std::string getFileName() const;\n  int getLineNumber() const;\n};\n\n/// Wrapper to provide functionality to jthrowable references\nclass FBEXPORT JThrowable : public JavaClass<JThrowable, JObject, jthrowable> {\n public:\n  static constexpr const char* kJavaDescriptor = \"Ljava/lang/Throwable;\";\n\n  using JStackTrace = JArrayClass<JStackTraceElement::javaobject>;\n\n  local_ref<JThrowable> initCause(alias_ref<JThrowable> cause);\n  local_ref<JStackTrace> getStackTrace();\n  void setStackTrace(alias_ref<JArrayClass<JStackTraceElement::javaobject>>);\n};\n\n#pragma push_macro(\"PlainJniRefMap\")\n#undef PlainJniRefMap\n#define PlainJniRefMap(rtype, jtype) \\\nnamespace detail { \\\ntemplate<> \\\nstruct RefReprType<jtype> { \\\n  using type = rtype; \\\n}; \\\n}\n\nPlainJniRefMap(JArrayBoolean, jbooleanArray);\nPlainJniRefMap(JArrayByte, jbyteArray);\nPlainJniRefMap(JArrayChar, jcharArray);\nPlainJniRefMap(JArrayShort, jshortArray);\nPlainJniRefMap(JArrayInt, jintArray);\nPlainJniRefMap(JArrayLong, jlongArray);\nPlainJniRefMap(JArrayFloat, jfloatArray);\nPlainJniRefMap(JArrayDouble, jdoubleArray);\nPlainJniRefMap(JObject, jobject);\nPlainJniRefMap(JClass, jclass);\nPlainJniRefMap(JString, jstring);\nPlainJniRefMap(JThrowable, jthrowable);\n\n#pragma pop_macro(\"PlainJniRefMap\")\n\n}}\n\n#include \"CoreClasses-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Exceptions.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n/**\n * @file Exceptions.h\n *\n * After invoking a JNI function that can throw a Java exception, the macro\n * @ref FACEBOOK_JNI_THROW_PENDING_EXCEPTION() or @ref FACEBOOK_JNI_THROW_EXCEPTION_IF()\n * should be invoked.\n *\n * IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT!\n * To use these methods you MUST call initExceptionHelpers() when your library is loaded.\n */\n\n#pragma once\n\n#include <alloca.h>\n#include <stdexcept>\n#include <string>\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n\n#include \"Common.h\"\n#include \"References.h\"\n#include \"CoreClasses.h\"\n\n#if defined(__ANDROID__) && defined(__ARM_ARCH_5TE__) && !defined(FBJNI_NO_EXCEPTION_PTR)\n// ARMv5 NDK does not support exception_ptr so we cannot use that when building for it.\n#define FBJNI_NO_EXCEPTION_PTR\n#endif\n\nnamespace facebook {\nnamespace jni {\n\nclass JThrowable;\n\nclass JCppException : public JavaClass<JCppException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/CppException;\";\n\n  static local_ref<JCppException> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n\n  static local_ref<JCppException> create(const std::exception& ex) {\n    return newInstance(make_jstring(ex.what()));\n  }\n};\n\n// JniException ////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * This class wraps a Java exception into a C++ exception; if the exception is routed back\n * to the Java side, it can be unwrapped and just look like a pure Java interaction. The class\n * is resilient to errors while creating the exception, falling back to some pre-allocated\n * exceptions if a new one cannot be allocated or populated.\n *\n * Note: the what() method of this class is not thread-safe (t6900503).\n */\nclass FBEXPORT JniException : public std::exception {\n public:\n  JniException();\n  ~JniException();\n\n  explicit JniException(alias_ref<jthrowable> throwable);\n\n  JniException(JniException &&rhs);\n\n  JniException(const JniException &other);\n\n  local_ref<JThrowable> getThrowable() const noexcept;\n\n  virtual const char* what() const noexcept;\n\n  void setJavaException() const noexcept;\n\n private:\n  global_ref<JThrowable> throwable_;\n  mutable std::string what_;\n  mutable bool isMessageExtracted_;\n  const static std::string kExceptionMessageFailure_;\n\n  void populateWhat() const noexcept;\n};\n\n// Exception throwing & translating functions //////////////////////////////////////////////////////\n\n// Functions that throw C++ exceptions\n\nstatic const int kMaxExceptionMessageBufferSize = 512;\n\n// These methods are the preferred way to throw a Java exception from\n// a C++ function.  They create and throw a C++ exception which wraps\n// a Java exception, so the C++ flow is interrupted. Then, when\n// translatePendingCppExceptionToJavaException is called at the\n// topmost level of the native stack, the wrapped Java exception is\n// thrown to the java caller.\ntemplate<typename... Args>\n[[noreturn]] void throwNewJavaException(const char* throwableName, const char* fmt, Args... args) {\n  int msgSize = snprintf(nullptr, 0, fmt, args...);\n\n  char *msg = (char*) alloca(msgSize + 1);\n  snprintf(msg, kMaxExceptionMessageBufferSize, fmt, args...);\n  throwNewJavaException(throwableName, msg);\n}\n\n// Identifies any pending C++ exception and throws it as a Java exception. If the exception can't\n// be thrown, it aborts the program.\nFBEXPORT void translatePendingCppExceptionToJavaException();\n\n#ifndef FBJNI_NO_EXCEPTION_PTR\nFBEXPORT local_ref<JThrowable> getJavaExceptionForCppException(std::exception_ptr ptr);\n#endif\n\nFBEXPORT local_ref<JThrowable> getJavaExceptionForCppBackTrace();\n\nFBEXPORT local_ref<JThrowable> getJavaExceptionForCppBackTrace(const char* msg);\n// For convenience, some exception names in java.lang are available here.\n\nconst char* const gJavaLangIllegalArgumentException = \"java/lang/IllegalArgumentException\";\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/File.h",
    "content": "/*\n * Copyright (c) 2016-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\nclass JFile : public JavaClass<JFile> {\n public:\n  static constexpr const char* kJavaDescriptor = \"Ljava/io/File;\";\n\n  // Define a method that calls into the represented Java class\n  std::string getAbsolutePath() {\n    static auto method = getClass()->getMethod<jstring()>(\"getAbsolutePath\");\n    return method(self())->toStdString();\n  }\n\n};\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Hybrid.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <memory>\n#include <type_traits>\n\n#include <fb/assert.h>\n#include <fb/visibility.h>\n\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\nclass BaseHybridClass {\npublic:\n  virtual ~BaseHybridClass() {}\n};\n\nstruct FBEXPORT HybridData : public JavaClass<HybridData> {\n  constexpr static auto kJavaDescriptor = \"Lcom/facebook/jni/HybridData;\";\n  static local_ref<HybridData> create();\n};\n\nclass HybridDestructor : public JavaClass<HybridDestructor> {\n  public:\n    static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/HybridData$Destructor;\";\n\n  template <typename T=detail::BaseHybridClass>\n  T* getNativePointer() {\n    static auto pointerField = javaClassStatic()->getField<jlong>(\"mNativePointer\");\n    auto* value = reinterpret_cast<detail::BaseHybridClass*>(getFieldValue(pointerField));\n    if (!value) {\n      throwNewJavaException(\"java/lang/NullPointerException\", \"java.lang.NullPointerException\");\n    }\n    return value;\n  }\n\n  template <typename T=detail::BaseHybridClass>\n  void setNativePointer(std::unique_ptr<T> new_value) {\n    static auto pointerField = javaClassStatic()->getField<jlong>(\"mNativePointer\");\n    auto old_value = std::unique_ptr<T>(reinterpret_cast<T*>(getFieldValue(pointerField)));\n    if (new_value && old_value) {\n        FBCRASH(\"Attempt to set C++ native pointer twice\");\n    }\n    setFieldValue(pointerField, reinterpret_cast<jlong>(new_value.release()));\n  }\n};\n\ntemplate<typename T>\ndetail::BaseHybridClass* getNativePointer(T t) {\n  return getHolder(t)->getNativePointer();\n}\n\ntemplate<typename T>\nvoid setNativePointer(T t, std::unique_ptr<detail::BaseHybridClass> new_value) {\n  getHolder(t)->setNativePointer(std::move(new_value));\n}\n\ntemplate<typename T>\nlocal_ref<HybridDestructor> getHolder(T t) {\n  static auto holderField = t->getClass()->template getField<HybridDestructor::javaobject>(\"mDestructor\");\n  return t->getFieldValue(holderField);\n}\n\n// JavaClass for HybridClassBase\nstruct FBEXPORT HybridClassBase : public JavaClass<HybridClassBase> {\n  constexpr static auto kJavaDescriptor = \"Lcom/facebook/jni/HybridClassBase;\";\n\n  static bool isHybridClassBase(alias_ref<jclass> jclass) {\n    return HybridClassBase::javaClassStatic()->isAssignableFrom(jclass);\n  }\n};\n\ntemplate <typename Base, typename Enabled = void>\nstruct HybridTraits {\n  // This static assert should actually always fail if we don't use one of the\n  // specializations below.\n  static_assert(\n      std::is_base_of<JObject, Base>::value ||\n      std::is_base_of<BaseHybridClass, Base>::value,\n      \"The base of a HybridClass must be either another HybridClass or derived from JObject.\");\n};\n\ntemplate <>\nstruct HybridTraits<BaseHybridClass> {\n using CxxBase = BaseHybridClass;\n using JavaBase = JObject;\n};\n\ntemplate <typename Base>\nstruct HybridTraits<\n    Base,\n    typename std::enable_if<std::is_base_of<BaseHybridClass, Base>::value>::type> {\n using CxxBase = Base;\n using JavaBase = typename Base::JavaPart;\n};\n\ntemplate <typename Base>\nstruct HybridTraits<\n    Base,\n    typename std::enable_if<std::is_base_of<JObject, Base>::value>::type> {\n using CxxBase = BaseHybridClass;\n using JavaBase = Base;\n};\n\n// convert to HybridClass* from jhybridobject\ntemplate <typename T>\nstruct FBEXPORT Convert<\n  T, typename std::enable_if<\n    std::is_base_of<BaseHybridClass, typename std::remove_pointer<T>::type>::value>::type> {\n  typedef typename std::remove_pointer<T>::type::jhybridobject jniType;\n  static T fromJni(jniType t) {\n    if (t == nullptr) {\n      return nullptr;\n    }\n    return wrap_alias(t)->cthis();\n  }\n  // There is no automatic return conversion for objects.\n};\n\ntemplate<typename T>\nstruct RefReprType<T, typename std::enable_if<std::is_base_of<BaseHybridClass, T>::value, void>::type> {\n  static_assert(std::is_same<T, void>::value,\n      \"HybridFoo (where HybridFoo derives from HybridClass<HybridFoo>) is not supported in this context. \"\n      \"For an xxx_ref<HybridFoo>, you may want: xxx_ref<HybridFoo::javaobject> or HybridFoo*.\");\n  using Repr = T;\n};\n\n\n}\n\ntemplate <typename T, typename Base = detail::BaseHybridClass>\nclass FBEXPORT HybridClass : public detail::HybridTraits<Base>::CxxBase {\npublic:\n  struct JavaPart : JavaClass<JavaPart, typename detail::HybridTraits<Base>::JavaBase> {\n    // At this point, T is incomplete, and so we cannot access\n    // T::kJavaDescriptor directly. jtype_traits support this escape hatch for\n    // such a case.\n    static constexpr const char* kJavaDescriptor = nullptr;\n    static std::string get_instantiated_java_descriptor();\n    static std::string get_instantiated_base_name();\n\n    using HybridType = T;\n\n    // This will reach into the java object and extract the C++ instance from\n    // the mHybridData and return it.\n    T* cthis();\n\n    friend class HybridClass;\n  };\n\n  using jhybridobject = typename JavaPart::javaobject;\n  using javaobject = typename JavaPart::javaobject;\n  typedef detail::HybridData::javaobject jhybriddata;\n\n  static alias_ref<JClass> javaClassStatic() {\n    return JavaPart::javaClassStatic();\n  }\n\n  static local_ref<JClass> javaClassLocal() {\n    std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2);\n    return findClassLocal(className.c_str());\n  }\n\nprotected:\n  typedef HybridClass HybridBase;\n\n  // This ensures that a C++ hybrid part cannot be created on its own\n  // by default.  If a hybrid wants to enable this, it can provide its\n  // own public ctor, or change the accessibility of this to public.\n  using detail::HybridTraits<Base>::CxxBase::CxxBase;\n\n  static void registerHybrid(std::initializer_list<NativeMethod> methods) {\n    javaClassStatic()->registerNatives(methods);\n  }\n\n  static local_ref<detail::HybridData> makeHybridData(std::unique_ptr<T> cxxPart) {\n    auto hybridData = detail::HybridData::create();\n    setNativePointer(hybridData, std::move(cxxPart));\n    return hybridData;\n  }\n\n  template <typename... Args>\n  static local_ref<detail::HybridData> makeCxxInstance(Args&&... args) {\n    return makeHybridData(std::unique_ptr<T>(new T(std::forward<Args>(args)...)));\n  }\n\n  template <typename... Args>\n  static void setCxxInstance(alias_ref<jhybridobject> o, Args&&... args) {\n    setNativePointer(o, std::unique_ptr<T>(new T(std::forward<Args>(args)...)));\n  }\n\npublic:\n  // Factory method for creating a hybrid object where the arguments\n  // are used to initialize the C++ part directly without passing them\n  // through java.  This method requires the Java part to have a ctor\n  // which takes a HybridData, and for the C++ part to have a ctor\n  // compatible with the arguments passed here.  For safety, the ctor\n  // can be private, and the hybrid declared a friend of its base, so\n  // the hybrid can only be created from here.\n  //\n  // Exception behavior: This can throw an exception if creating the\n  // C++ object fails, or any JNI methods throw.\n  template <typename... Args>\n  static local_ref<JavaPart> newObjectCxxArgs(Args&&... args) {\n    static bool isHybrid = detail::HybridClassBase::isHybridClassBase(javaClassStatic());\n    auto cxxPart = std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n\n    local_ref<JavaPart> result;\n    if (isHybrid) {\n      result = JavaPart::newInstance();\n      setNativePointer(result, std::move(cxxPart));\n    }\n    else {\n      auto hybridData = makeHybridData(std::move(cxxPart));\n      result = JavaPart::newInstance(hybridData);\n    }\n\n    return result;\n  }\n\n // TODO? Create reusable interface for Allocatable classes and use it to\n  // strengthen type-checking (and possibly provide a default\n  // implementation of allocate().)\n  template <typename... Args>\n  static local_ref<jhybridobject> allocateWithCxxArgs(Args&&... args) {\n    auto hybridData = makeCxxInstance(std::forward<Args>(args)...);\n    static auto allocateMethod =\n        javaClassStatic()->template getStaticMethod<jhybridobject(jhybriddata)>(\"allocate\");\n    return allocateMethod(javaClassStatic(), hybridData.get());\n  }\n\n  // Factory method for creating a hybrid object where the arguments\n  // are passed to the java ctor.\n  template <typename... Args>\n  static local_ref<JavaPart> newObjectJavaArgs(Args&&... args) {\n    return JavaPart::newInstance(std::move(args)...);\n  }\n\n  // If a hybrid class throws an exception which derives from\n  // std::exception, it will be passed to mapException on the hybrid\n  // class, or nearest ancestor.  This allows boilerplate exception\n  // translation code (for example, calling throwNewJavaException on a\n  // particular java class) to be hoisted to a common function.  If\n  // mapException returns, then the std::exception will be translated\n  // to Java.\n  static void mapException(const std::exception& ex) {}\n};\n\ntemplate <typename T, typename B>\ninline T* HybridClass<T, B>::JavaPart::cthis() {\n  detail::BaseHybridClass* result = 0;\n  static bool isHybrid = detail::HybridClassBase::isHybridClassBase(this->getClass());\n  if (isHybrid) {\n    result = getNativePointer(this);\n  } else {\n    static auto field =\n      HybridClass<T, B>::JavaPart::javaClassStatic()->template getField<detail::HybridData::javaobject>(\"mHybridData\");\n    auto hybridData = this->getFieldValue(field);\n    if (!hybridData) {\n      throwNewJavaException(\"java/lang/NullPointerException\", \"java.lang.NullPointerException\");\n    }\n\n    result = getNativePointer(hybridData);\n  }\n\n  // This would require some serious programmer error.\n  FBASSERTMSGF(result != 0, \"Incorrect C++ type in hybrid field\");\n  // I'd like to use dynamic_cast here, but -fno-rtti is the default.\n  return static_cast<T*>(result);\n};\n\ntemplate <typename T, typename B>\n/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_java_descriptor() {\n  return T::kJavaDescriptor;\n}\n\ntemplate <typename T, typename B>\n/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_base_name() {\n  auto name = get_instantiated_java_descriptor();\n  return name.substr(1, name.size() - 2);\n}\n\n// Given a *_ref object which refers to a hybrid class, this will reach inside\n// of it, find the mHybridData, extract the C++ instance pointer, cast it to\n// the appropriate type, and return it.\ntemplate <typename T>\ninline auto cthis(T jthis) -> decltype(jthis->cthis()) {\n  return jthis->cthis();\n}\n\nvoid HybridDataOnLoad();\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Iterator-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\ntemplate <typename E>\nstruct IteratorHelper : public JavaClass<IteratorHelper<E>> {\n  constexpr static auto kJavaDescriptor = \"Lcom/facebook/jni/IteratorHelper;\";\n\n  typedef local_ref<E> value_type;\n  typedef ptrdiff_t difference_type;\n  typedef value_type* pointer;\n  typedef value_type& reference;\n  typedef std::forward_iterator_tag iterator_category;\n\n  typedef JavaClass<IteratorHelper<E>> JavaBase_;\n\n  bool hasNext() const {\n    static auto hasNextMethod =\n      JavaBase_::javaClassStatic()->template getMethod<jboolean()>(\"hasNext\");\n    return hasNextMethod(JavaBase_::self());\n  }\n\n  value_type next() {\n    static auto elementField =\n      JavaBase_::javaClassStatic()->template getField<jobject>(\"mElement\");\n    return dynamic_ref_cast<E>(JavaBase_::getFieldValue(elementField));\n  }\n\n  static void reset(value_type& v) {\n    v.reset();\n  }\n};\n\ntemplate <typename K, typename V>\nstruct MapIteratorHelper : public JavaClass<MapIteratorHelper<K,V>> {\n  constexpr static auto kJavaDescriptor = \"Lcom/facebook/jni/MapIteratorHelper;\";\n\n  typedef std::pair<local_ref<K>, local_ref<V>> value_type;\n\n  typedef JavaClass<MapIteratorHelper<K,V>> JavaBase_;\n\n  bool hasNext() const {\n    static auto hasNextMethod =\n      JavaBase_::javaClassStatic()->template getMethod<jboolean()>(\"hasNext\");\n    return hasNextMethod(JavaBase_::self());\n  }\n\n  value_type next() {\n    static auto keyField = JavaBase_::javaClassStatic()->template getField<jobject>(\"mKey\");\n    static auto valueField = JavaBase_::javaClassStatic()->template getField<jobject>(\"mValue\");\n    return std::make_pair(dynamic_ref_cast<K>(JavaBase_::getFieldValue(keyField)),\n                          dynamic_ref_cast<V>(JavaBase_::getFieldValue(valueField)));\n  }\n\n  static void reset(value_type& v) {\n    v.first.reset();\n    v.second.reset();\n  }\n};\n\ntemplate <typename T>\nclass Iterator {\n public:\n  typedef typename T::value_type value_type;\n  typedef ptrdiff_t difference_type;\n  typedef value_type* pointer;\n  typedef value_type& reference;\n  typedef std::input_iterator_tag iterator_category;\n\n  // begin ctor\n  Iterator(global_ref<typename T::javaobject>&& helper)\n      : helper_(std::move(helper))\n      , i_(-1) {\n    ++(*this);\n  }\n\n  // end ctor\n  Iterator()\n      : i_(-1) {}\n\n  bool operator==(const Iterator& it) const { return i_ == it.i_; }\n  bool operator!=(const Iterator& it) const { return !(*this == it); }\n  const value_type& operator*() const { assert(i_ != -1); return entry_; }\n  const value_type* operator->() const { assert(i_ != -1); return &entry_; }\n  Iterator& operator++() {  // preincrement\n    bool hasNext = helper_->hasNext();\n    if (hasNext) {\n      ++i_;\n      entry_ = helper_->next();\n    } else {\n      i_ = -1;\n      helper_->reset(entry_);\n    }\n    return *this;\n  }\n  Iterator operator++(int) {  // postincrement\n    Iterator ret;\n    ret.i_ = i_;\n    ret.entry_ = std::move(entry_);\n    ++(*this);\n    return ret;\n  }\n\n  global_ref<typename T::javaobject> helper_;\n  // set to -1 at end\n  std::ptrdiff_t i_;\n  value_type entry_;\n};\n\n}\n\ntemplate <typename E>\nstruct JIterator<E>::Iterator : public detail::Iterator<detail::IteratorHelper<E>> {\n  using detail::Iterator<detail::IteratorHelper<E>>::Iterator;\n};\n\ntemplate <typename E>\ntypename JIterator<E>::Iterator JIterator<E>::begin() const {\n  static auto ctor = detail::IteratorHelper<E>::javaClassStatic()->\n    template getConstructor<typename detail::IteratorHelper<E>::javaobject(\n                              typename JIterator<E>::javaobject)>();\n  return Iterator(\n    make_global(\n      detail::IteratorHelper<E>::javaClassStatic()->newObject(ctor, this->self())));\n}\n\ntemplate <typename E>\ntypename JIterator<E>::Iterator JIterator<E>::end() const {\n  return Iterator();\n}\n\ntemplate <typename E>\nstruct JIterable<E>::Iterator : public detail::Iterator<detail::IteratorHelper<E>> {\n  using detail::Iterator<detail::IteratorHelper<E>>::Iterator;\n};\n\ntemplate <typename E>\ntypename JIterable<E>::Iterator JIterable<E>::begin() const {\n  static auto ctor = detail::IteratorHelper<E>::javaClassStatic()->\n    template getConstructor<typename detail::IteratorHelper<E>::javaobject(\n                              typename JIterable<E>::javaobject)>();\n  return Iterator(\n    make_global(\n      detail::IteratorHelper<E>::javaClassStatic()->newObject(ctor, this->self())));\n}\n\ntemplate <typename E>\ntypename JIterable<E>::Iterator JIterable<E>::end() const {\n  return Iterator();\n}\n\ntemplate <typename E>\nsize_t JCollection<E>::size() const {\n  static auto sizeMethod =\n    JCollection<E>::javaClassStatic()->template getMethod<jint()>(\"size\");\n  return sizeMethod(this->self());\n}\n\ntemplate <typename K, typename V>\nstruct JMap<K,V>::Iterator : public detail::Iterator<detail::MapIteratorHelper<K,V>> {\n  using detail::Iterator<detail::MapIteratorHelper<K,V>>::Iterator;\n};\n\ntemplate <typename K, typename V>\nsize_t JMap<K,V>::size() const {\n  static auto sizeMethod =\n    JMap<K,V>::javaClassStatic()->template getMethod<jint()>(\"size\");\n  return sizeMethod(this->self());\n}\n\ntemplate <typename K, typename V>\ntypename JMap<K,V>::Iterator JMap<K,V>::begin() const {\n  static auto ctor = detail::MapIteratorHelper<K,V>::javaClassStatic()->\n    template getConstructor<typename detail::MapIteratorHelper<K,V>::javaobject(\n                              typename JMap<K,V>::javaobject)>();\n  return Iterator(\n    make_global(\n      detail::MapIteratorHelper<K,V>::javaClassStatic()->newObject(ctor, this->self())));\n}\n\ntemplate <typename K, typename V>\ntypename JMap<K,V>::Iterator JMap<K,V>::end() const {\n  return Iterator();\n}\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Iterator.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\n/**\n * JavaClass which represents a reference to a java.util.Iterator instance.  It\n * provides begin()/end() methods to provide C++-style iteration over the\n * underlying collection.  The class has a template parameter for the element\n * type, which defaults to jobject.  For example:\n *\n * alias_ref<JIterator<jstring>::javaobject> my_iter = ...;\n *\n * In the simplest case, it can be used just as alias_ref<JIterator<>::javaobject>,\n * for example in a method declaration.\n */\ntemplate <typename E = jobject>\nstruct JIterator : JavaClass<JIterator<E>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/util/Iterator;\";\n\n  struct Iterator;\n\n  /**\n   * To iterate:\n   *\n   * for (const auto& element : *jiter) { ... }\n   *\n   * The JIterator iterator value_type is local_ref<E>, containing a reference\n   * to an element instance.\n   *\n   * If the Iterator returns objects whch are not convertible to the given\n   * element type, iteration will throw a java ClassCastException.\n   *\n   * For example, to convert an iterator over a collection of java strings to\n   * an std::vector of std::strings:\n   *\n   * std::vector<std::string> vs;\n   * for (const auto& elem : *jiter) {\n   *    vs.push_back(elem->toStdString());\n   * }\n   *\n   * Or if you prefer using std algorithms:\n   *\n   * std::vector<std::string> vs;\n   * std::transform(jiter->begin(), jiter->end(), std::back_inserter(vs),\n   *                [](const local_ref<jstring>& elem) { return elem->toStdString(); });\n   *\n   * The iterator is a InputIterator.\n   */\n  Iterator begin() const;\n  Iterator end() const;\n};\n\n/**\n * Similar to JIterator, except this represents any object which implements the\n * java.lang.Iterable interface. It will create the Java Iterator as a part of\n * begin().\n */\ntemplate <typename E = jobject>\nstruct JIterable : JavaClass<JIterable<E>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/lang/Iterable;\";\n\n  struct Iterator;\n\n  Iterator begin() const;\n  Iterator end() const;\n};\n\n/**\n * JavaClass types which represent Collection, List, and Set are also provided.\n * These preserve the Java class heirarchy.\n */\ntemplate <typename E = jobject>\nstruct JCollection : JavaClass<JCollection<E>, JIterable<E>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/util/Collection;\";\n\n  /**\n   * Returns the number of elements in the collection.\n   */\n  size_t size() const;\n};\n\ntemplate <typename E = jobject>\nstruct JList : JavaClass<JList<E>, JCollection<E>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/util/List;\";\n};\n\ntemplate <typename E = jobject>\nstruct JSet : JavaClass<JSet<E>, JCollection<E>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/util/Set;\";\n};\n\n/**\n * JavaClass which represents a reference to a java.util.Map instance.  It adds\n * wrappers around Java methods, including begin()/end() methods to provide\n * C++-style iteration over the Java Map.  The class has template parameters\n * for the key and value types, which default to jobject.  For example:\n *\n * alias_ref<JMap<jstring, MyJClass::javaobject>::javaobject> my_map = ...;\n *\n * In the simplest case, it can be used just as alias_ref<JMap<>::javaobject>,\n * for example in a method declaration.\n */\ntemplate <typename K = jobject, typename V = jobject>\nstruct JMap : JavaClass<JMap<K,V>> {\n  constexpr static auto kJavaDescriptor = \"Ljava/util/Map;\";\n\n  struct Iterator;\n\n  /**\n   * Returns the number of pairs in the map.\n   */\n  size_t size() const;\n\n  /**\n   * To iterate over the Map:\n   *\n   * for (const auto& entry : *jmap) { ... }\n   *\n   * The JMap iterator value_type is std::pair<local_ref<K>, local_ref<V>>\n   * containing references to key and value instances.\n   *\n   * If the Map contains objects whch are not convertible to the given key and\n   * value types, iteration will throw a java ClassCastException.\n   *\n   * The iterator is a InputIterator.\n   */\n  Iterator begin() const;\n  Iterator end() const;\n};\n\n}\n}\n\n#include \"Iterator-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/JThread.h",
    "content": "/*\n * Copyright (c) 2016-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n#include \"NativeRunnable.h\"\n\nnamespace facebook {\nnamespace jni {\n\nclass JThread : public JavaClass<JThread> {\n public:\n  static constexpr const char* kJavaDescriptor = \"Ljava/lang/Thread;\";\n\n  void start() {\n    static auto method = javaClassStatic()->getMethod<void()>(\"start\");\n    method(self());\n  }\n\n  void join() {\n    static auto method = javaClassStatic()->getMethod<void()>(\"join\");\n    method(self());\n  }\n\n  static local_ref<JThread> create(std::function<void()>&& runnable) {\n    auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable));\n    return newInstance(static_ref_cast<JRunnable::javaobject>(jrunnable));\n  }\n};\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/JWeakReference.h",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#pragma once\n\n#include <fb/visibility.h>\n\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\n/**\n * Wrap Java's WeakReference instead of using JNI WeakGlobalRefs.\n * A WeakGlobalRef can yield a strong reference even after the object has been\n  * finalized. See comment in the djinni library.\n * https://github.com/dropbox/djinni/blob/master/support-lib/jni/djinni_support.hpp\n */\ntemplate<typename T = jobject>\nclass JWeakReference : public JavaClass<JWeakReference<T>> {\n\n typedef JavaClass<JWeakReference<T>> JavaBase_;\n\n public:\n  static constexpr const char* kJavaDescriptor = \"Ljava/lang/ref/WeakReference;\";\n\n  static local_ref<JWeakReference<T>> newInstance(alias_ref<T> object) {\n    return JavaBase_::newInstance(static_ref_cast<jobject>(object));\n  }\n\n  local_ref<T> get() const {\n    static auto method = JavaBase_::javaClassStatic()->template getMethod<jobject()>(\"get\");\n    return static_ref_cast<T>(method(JavaBase_::self()));\n  }\n};\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Meta-forward.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\nnamespace facebook {\nnamespace jni {\n\ntemplate<typename F>\nclass JMethod;\ntemplate<typename F>\nclass JStaticMethod;\ntemplate<typename F>\nclass JNonvirtualMethod;\ntemplate<typename F>\nstruct JConstructor;\ntemplate<typename F>\nclass JField;\ntemplate<typename F>\nclass JStaticField;\n\n/// Type traits for Java types (currently providing Java type descriptors)\ntemplate<typename T>\nstruct jtype_traits;\n\n/// Type traits for Java methods (currently providing Java type descriptors)\ntemplate<typename F>\nstruct jmethod_traits;\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Meta-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <jni.h>\n\n#include \"Common.h\"\n#include \"Exceptions.h\"\n#include \"MetaConvert.h\"\n#include \"References.h\"\n#include \"Boxed.h\"\n\n#if defined(__ANDROID__)\n#  include <fb/Build.h>\n#endif\n\nnamespace facebook {\nnamespace jni {\n\n// JMethod /////////////////////////////////////////////////////////////////////////////////////////\n\ninline JMethodBase::JMethodBase(jmethodID method_id) noexcept\n  : method_id_{method_id}\n{}\n\ninline JMethodBase::operator bool() const noexcept {\n  return method_id_ != nullptr;\n}\n\ninline jmethodID JMethodBase::getId() const noexcept {\n  return method_id_;\n}\n\nnamespace {\n\ntemplate <int idx, typename... Args>\nstruct ArgsArraySetter;\n\ntemplate <int idx, typename Arg, typename... Args>\nstruct ArgsArraySetter<idx, Arg, Args...> {\n  static void set(alias_ref<JArrayClass<jobject>::javaobject> array, Arg arg0, Args... args) {\n    // TODO(xxxxxxxx): Use Convert<Args>... to do conversions like the fast path.\n    (*array)[idx] = autobox(arg0);\n    ArgsArraySetter<idx + 1, Args...>::set(array, args...);\n  }\n};\n\ntemplate <int idx>\nstruct ArgsArraySetter<idx> {\n  static void set(alias_ref<JArrayClass<jobject>::javaobject> array) {\n  }\n};\n\ntemplate <typename... Args>\nlocal_ref<JArrayClass<jobject>::javaobject> makeArgsArray(Args... args) {\n  auto arr = JArrayClass<jobject>::newArray(sizeof...(args));\n  ArgsArraySetter<0, Args...>::set(arr, args...);\n  return arr;\n}\n\n\ninline bool needsSlowPath(alias_ref<jobject> obj) {\n#if defined(__ANDROID__)\n  // On Android 6.0, art crashes when attempting to call a function on a Proxy.\n  // So, when we detect that case we must use the safe, slow workaround. That is,\n  // we resolve the method id to the corresponding java.lang.reflect.Method object\n  // and make the call via it's invoke() method.\n  static auto is_bad_android = build::Build::getAndroidSdk() == 23;\n\n  if (!is_bad_android) return false;\n  static auto proxy_class = findClassStatic(\"java/lang/reflect/Proxy\");\n  return obj->isInstanceOf(proxy_class);\n#else\n  return false;\n#endif\n}\n\n}\n\ntemplate<typename... Args>\ninline void JMethod<void(Args...)>::operator()(alias_ref<jobject> self, Args... args) {\n  const auto env = Environment::current();\n  env->CallVoidMethod(\n        self.get(),\n        getId(),\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n}\n\n#pragma push_macro(\"DEFINE_PRIMITIVE_CALL\")\n#undef DEFINE_PRIMITIVE_CALL\n#define DEFINE_PRIMITIVE_CALL(TYPE, METHOD)                                                    \\\ntemplate<typename... Args>                                                                     \\\ninline TYPE JMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, Args... args) {        \\\n  const auto env = internal::getEnv();                                                         \\\n  auto result = env->Call ## METHOD ## Method(                                                 \\\n        self.get(),                                                                            \\\n        getId(),                                                                               \\\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...); \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                      \\\n  return result;                                                                               \\\n}\n\nDEFINE_PRIMITIVE_CALL(jboolean, Boolean)\nDEFINE_PRIMITIVE_CALL(jbyte, Byte)\nDEFINE_PRIMITIVE_CALL(jchar, Char)\nDEFINE_PRIMITIVE_CALL(jshort, Short)\nDEFINE_PRIMITIVE_CALL(jint, Int)\nDEFINE_PRIMITIVE_CALL(jlong, Long)\nDEFINE_PRIMITIVE_CALL(jfloat, Float)\nDEFINE_PRIMITIVE_CALL(jdouble, Double)\n#pragma pop_macro(\"DEFINE_PRIMITIVE_CALL\")\n\n/// JMethod specialization for references that wraps the return value in a @ref local_ref\ntemplate<typename R, typename... Args>\nclass JMethod<R(Args...)> : public JMethodBase {\n public:\n   // TODO: static_assert is jobject-derived or local_ref jobject\n  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;\n  static_assert(IsPlainJniReference<JniRet>(), \"JniRet must be a JNI reference\");\n  using JMethodBase::JMethodBase;\n  JMethod() noexcept {};\n  JMethod(const JMethod& other) noexcept = default;\n\n  /// Invoke a method and return a local reference wrapping the result\n  local_ref<JniRet> operator()(alias_ref<jobject> self, Args... args);\n\n  friend class JClass;\n};\n\ntemplate<typename R, typename... Args>\ninline auto JMethod<R(Args...)>::operator()(alias_ref<jobject> self, Args... args) -> local_ref<JniRet> {\n  const auto env = Environment::current();\n  auto result = env->CallObjectMethod(\n      self.get(),\n      getId(),\n      detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  return adopt_local(static_cast<JniRet>(result));\n}\n\ntemplate<typename... Args>\ninline void JStaticMethod<void(Args...)>::operator()(alias_ref<jclass> cls, Args... args) {\n  const auto env = internal::getEnv();\n  env->CallStaticVoidMethod(\n        cls.get(),\n        getId(),\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n}\n\n#pragma push_macro(\"DEFINE_PRIMITIVE_STATIC_CALL\")\n#undef DEFINE_PRIMITIVE_STATIC_CALL\n#define DEFINE_PRIMITIVE_STATIC_CALL(TYPE, METHOD)                                             \\\ntemplate<typename... Args>                                                                     \\\ninline TYPE JStaticMethod<TYPE(Args...)>::operator()(alias_ref<jclass> cls, Args... args) {    \\\n  const auto env = internal::getEnv();                                                         \\\n  auto result = env->CallStatic ## METHOD ## Method(                                           \\\n        cls.get(),                                                                             \\\n        getId(),                                                                               \\\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...); \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                      \\\n        return result;                                                                         \\\n}\n\nDEFINE_PRIMITIVE_STATIC_CALL(jboolean, Boolean)\nDEFINE_PRIMITIVE_STATIC_CALL(jbyte, Byte)\nDEFINE_PRIMITIVE_STATIC_CALL(jchar, Char)\nDEFINE_PRIMITIVE_STATIC_CALL(jshort, Short)\nDEFINE_PRIMITIVE_STATIC_CALL(jint, Int)\nDEFINE_PRIMITIVE_STATIC_CALL(jlong, Long)\nDEFINE_PRIMITIVE_STATIC_CALL(jfloat, Float)\nDEFINE_PRIMITIVE_STATIC_CALL(jdouble, Double)\n#pragma pop_macro(\"DEFINE_PRIMITIVE_STATIC_CALL\")\n\n/// JStaticMethod specialization for references that wraps the return value in a @ref local_ref\ntemplate<typename R, typename... Args>\nclass JStaticMethod<R(Args...)> : public JMethodBase {\n\n public:\n  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;\n  static_assert(IsPlainJniReference<JniRet>(), \"T* must be a JNI reference\");\n  using JMethodBase::JMethodBase;\n  JStaticMethod() noexcept {};\n  JStaticMethod(const JStaticMethod& other) noexcept = default;\n\n  /// Invoke a method and return a local reference wrapping the result\n  local_ref<JniRet> operator()(alias_ref<jclass> cls, Args... args) {\n    const auto env = internal::getEnv();\n    auto result = env->CallStaticObjectMethod(\n          cls.get(),\n          getId(),\n          detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n    return adopt_local(static_cast<JniRet>(result));\n  }\n\n  friend class JClass;\n};\n\ntemplate<typename... Args>\ninline void\nJNonvirtualMethod<void(Args...)>::operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args) {\n  const auto env = internal::getEnv();\n  env->CallNonvirtualVoidMethod(\n        self.get(),\n        cls.get(),\n        getId(),\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n}\n\n#pragma push_macro(\"DEFINE_PRIMITIVE_NON_VIRTUAL_CALL\")\n#undef DEFINE_PRIMITIVE_NON_VIRTUAL_CALL\n#define DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(TYPE, METHOD)                                                      \\\ntemplate<typename... Args>                                                                                   \\\ninline TYPE                                                                                                  \\\nJNonvirtualMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args) { \\\n  const auto env = internal::getEnv();                                                                       \\\n  auto result = env->CallNonvirtual ## METHOD ## Method(                                                     \\\n        self.get(),                                                                                          \\\n        cls.get(),                                                                                           \\\n        getId(),                                                                                             \\\n        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);               \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                                    \\\n  return result;                                                                                             \\\n}\n\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jboolean, Boolean)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jbyte, Byte)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jchar, Char)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jshort, Short)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jint, Int)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jlong, Long)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jfloat, Float)\nDEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jdouble, Double)\n#pragma pop_macro(\"DEFINE_PRIMITIVE_NON_VIRTUAL_CALL\")\n\n/// JNonvirtualMethod specialization for references that wraps the return value in a @ref local_ref\ntemplate<typename R, typename... Args>\nclass JNonvirtualMethod<R(Args...)> : public JMethodBase {\n public:\n  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;\n  static_assert(IsPlainJniReference<JniRet>(), \"T* must be a JNI reference\");\n  using JMethodBase::JMethodBase;\n  JNonvirtualMethod() noexcept {};\n  JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default;\n\n  /// Invoke a method and return a local reference wrapping the result\n  local_ref<JniRet> operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args){\n    const auto env = internal::getEnv();\n    auto result = env->CallNonvirtualObjectMethod(\n          self.get(),\n          cls.get(),\n          getId(),\n          detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);\n    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n    return adopt_local(static_cast<JniRet>(result));\n  }\n\n  friend class JClass;\n};\n\ntemplate <typename... Args>\nlocal_ref<jobject> slowCall(jmethodID method_id, alias_ref<jobject> self, Args... args) {\n    static auto invoke = findClassStatic(\"java/lang/reflect/Method\")\n      ->getMethod<jobject(jobject, JArrayClass<jobject>::javaobject)>(\"invoke\");\n    // TODO(xxxxxxx): Provide fbjni interface to ToReflectedMethod.\n    auto reflected = adopt_local(Environment::current()->ToReflectedMethod(self->getClass().get(), method_id, JNI_FALSE));\n    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n    if (!reflected) throw std::runtime_error(\"Unable to get reflected java.lang.reflect.Method\");\n    auto argsArray = makeArgsArray(args...);\n    // No need to check for exceptions since invoke is itself a JMethod that will do that for us.\n    return invoke(reflected, self.get(), argsArray.get());\n}\n\n\n// JField<T> ///////////////////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T>\ninline JField<T>::JField(jfieldID field) noexcept\n  : field_id_{field}\n{}\n\ntemplate<typename T>\ninline JField<T>::operator bool() const noexcept {\n  return field_id_ != nullptr;\n}\n\ntemplate<typename T>\ninline jfieldID JField<T>::getId() const noexcept {\n  return field_id_;\n}\n\n#pragma push_macro(\"DEFINE_FIELD_PRIMITIVE_GET_SET\")\n#undef DEFINE_FIELD_PRIMITIVE_GET_SET\n#define DEFINE_FIELD_PRIMITIVE_GET_SET(TYPE, METHOD)                 \\\ntemplate<>                                                           \\\ninline TYPE JField<TYPE>::get(jobject object) const noexcept {       \\\n  const auto env = internal::getEnv();                               \\\n  return env->Get ## METHOD ## Field(object, field_id_);             \\\n}                                                                    \\\n                                                                     \\\ntemplate<>                                                           \\\ninline void JField<TYPE>::set(jobject object, TYPE value) noexcept { \\\n  const auto env = internal::getEnv();                               \\\n  env->Set ## METHOD ## Field(object, field_id_, value);             \\\n}\n\nDEFINE_FIELD_PRIMITIVE_GET_SET(jboolean, Boolean)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jbyte, Byte)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jchar, Char)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jshort, Short)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jint, Int)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jlong, Long)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jfloat, Float)\nDEFINE_FIELD_PRIMITIVE_GET_SET(jdouble, Double)\n#pragma pop_macro(\"DEFINE_FIELD_PRIMITIVE_GET_SET\")\n\ntemplate<typename T>\ninline T JField<T>::get(jobject object) const noexcept {\n  return static_cast<T>(internal::getEnv()->GetObjectField(object, field_id_));\n}\n\ntemplate<typename T>\ninline void JField<T>::set(jobject object, T value) noexcept {\n  internal::getEnv()->SetObjectField(object, field_id_, static_cast<jobject>(value));\n}\n\n// JStaticField<T> /////////////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T>\ninline JStaticField<T>::JStaticField(jfieldID field) noexcept\n  : field_id_{field}\n{}\n\ntemplate<typename T>\ninline JStaticField<T>::operator bool() const noexcept {\n  return field_id_ != nullptr;\n}\n\ntemplate<typename T>\ninline jfieldID JStaticField<T>::getId() const noexcept {\n  return field_id_;\n}\n\n#pragma push_macro(\"DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET\")\n#undef DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET\n#define DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(TYPE, METHOD)                \\\ntemplate<>                                                                 \\\ninline TYPE JStaticField<TYPE>::get(jclass jcls) const noexcept {          \\\n  const auto env = internal::getEnv();                                     \\\n  return env->GetStatic ## METHOD ## Field(jcls, field_id_);               \\\n}                                                                          \\\n                                                                           \\\ntemplate<>                                                                 \\\ninline void JStaticField<TYPE>::set(jclass jcls, TYPE value) noexcept {    \\\n  const auto env = internal::getEnv();                                     \\\n  env->SetStatic ## METHOD ## Field(jcls, field_id_, value);               \\\n}\n\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jboolean, Boolean)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jbyte, Byte)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jchar, Char)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jshort, Short)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jint, Int)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jlong, Long)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jfloat, Float)\nDEFINE_STATIC_FIELD_PRIMITIVE_GET_SET(jdouble, Double)\n#pragma pop_macro(\"DEFINE_STATIC_FIELD_PRIMITIVE_GET_SET\")\n\ntemplate<typename T>\ninline T JStaticField<T>::get(jclass jcls) const noexcept {\n  const auto env = internal::getEnv();\n  return static_cast<T>(env->GetStaticObjectField(jcls, field_id_));\n}\n\ntemplate<typename T>\ninline void JStaticField<T>::set(jclass jcls, T value) noexcept {\n  internal::getEnv()->SetStaticObjectField(jcls, field_id_, value);\n}\n\n\n// jmethod_traits //////////////////////////////////////////////////////////////////////////////////\n\n// TODO(T6608405) Adapt this to implement a register natives method that requires no descriptor\nnamespace internal {\n\ntemplate<typename Head>\ninline std::string JavaDescriptor() {\n  return jtype_traits<Head>::descriptor();\n}\n\ntemplate<typename Head, typename Elem, typename... Tail>\ninline std::string JavaDescriptor() {\n  return JavaDescriptor<Head>() + JavaDescriptor<Elem, Tail...>();\n}\n\ntemplate<typename R, typename Arg1, typename... Args>\ninline std::string JMethodDescriptor() {\n  return \"(\" + JavaDescriptor<Arg1, Args...>() + \")\" + JavaDescriptor<R>();\n}\n\ntemplate<typename R>\ninline std::string JMethodDescriptor() {\n  return \"()\" + JavaDescriptor<R>();\n}\n\n} // internal\n\ntemplate<typename R, typename... Args>\ninline std::string jmethod_traits<R(Args...)>::descriptor() {\n  return internal::JMethodDescriptor<R, Args...>();\n}\n\ntemplate<typename R, typename... Args>\ninline std::string jmethod_traits<R(Args...)>::constructor_descriptor() {\n  return internal::JMethodDescriptor<void, Args...>();\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Meta.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n/** @file meta.h\n *\n * Provides wrappers for meta data such as methods and fields.\n */\n\n#pragma once\n\n#include <type_traits>\n#include <string>\n\n#include <jni.h>\n\n#include \"References-forward.h\"\n\n#ifdef __ANDROID__\n# include <android/log.h>\n# define XLOG_TAG \"fb-jni\"\n# define XLOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, XLOG_TAG, __VA_ARGS__)\n# define XLOGD(...) __android_log_print(ANDROID_LOG_DEBUG, XLOG_TAG, __VA_ARGS__)\n# define XLOGI(...) __android_log_print(ANDROID_LOG_INFO, XLOG_TAG, __VA_ARGS__)\n# define XLOGW(...) __android_log_print(ANDROID_LOG_WARN, XLOG_TAG, __VA_ARGS__)\n# define XLOGE(...) __android_log_print(ANDROID_LOG_ERROR, XLOG_TAG, __VA_ARGS__)\n# define XLOGWTF(...) __android_log_print(ANDROID_LOG_FATAL, XLOG_TAG, __VA_ARGS__)\n#endif\n\nnamespace facebook {\nnamespace jni {\n\n// This will get the reflected Java Method from the method_id, get it's invoke\n// method, and call the method via that. This shouldn't ever be needed, but\n// Android 6.0 crashes when calling a method on a java.lang.Proxy via jni.\ntemplate <typename... Args>\nlocal_ref<jobject> slowCall(jmethodID method_id, alias_ref<jobject> self, Args... args);\n\nclass JObject;\n\n\n/// Wrapper of a jmethodID. Provides a common base for JMethod specializations\nclass JMethodBase {\n public:\n  /// Verify that the method is valid\n  explicit operator bool() const noexcept;\n\n  /// Access the wrapped id\n  jmethodID getId() const noexcept;\n\n protected:\n  /// Create a wrapper of a method id\n  explicit JMethodBase(jmethodID method_id = nullptr) noexcept;\n\n private:\n  jmethodID method_id_;\n};\n\n\n/// Representation of a jmethodID\ntemplate<typename F>\nclass JMethod;\n\n/// @cond INTERNAL\n#pragma push_macro(\"DEFINE_PRIMITIVE_METHOD_CLASS\")\n\n#undef DEFINE_PRIMITIVE_METHOD_CLASS\n\n// Defining JMethod specializations based on return value\n#define DEFINE_PRIMITIVE_METHOD_CLASS(TYPE)                                      \\\ntemplate<typename... Args>                                                       \\\nclass JMethod<TYPE(Args...)> : public JMethodBase {                              \\\n public:                                                                         \\\n  static_assert(std::is_void<TYPE>::value || IsJniPrimitive<TYPE>(),             \\\n      \"TYPE must be primitive or void\");                                         \\\n                                                                                 \\\n  using JMethodBase::JMethodBase;                                                \\\n  JMethod() noexcept {};                                                         \\\n  JMethod(const JMethod& other) noexcept = default;                              \\\n                                                                                 \\\n  TYPE operator()(alias_ref<jobject> self, Args... args);                        \\\n                                                                                 \\\n  friend class JClass;                                                           \\\n}\n\nDEFINE_PRIMITIVE_METHOD_CLASS(void);\nDEFINE_PRIMITIVE_METHOD_CLASS(jboolean);\nDEFINE_PRIMITIVE_METHOD_CLASS(jbyte);\nDEFINE_PRIMITIVE_METHOD_CLASS(jchar);\nDEFINE_PRIMITIVE_METHOD_CLASS(jshort);\nDEFINE_PRIMITIVE_METHOD_CLASS(jint);\nDEFINE_PRIMITIVE_METHOD_CLASS(jlong);\nDEFINE_PRIMITIVE_METHOD_CLASS(jfloat);\nDEFINE_PRIMITIVE_METHOD_CLASS(jdouble);\n\n#pragma pop_macro(\"DEFINE_PRIMITIVE_METHOD_CLASS\")\n/// @endcond\n\n\n/// Convenience type representing constructors\n/// These should only be used with JClass::getConstructor and JClass::newObject.\ntemplate<typename F>\nstruct JConstructor : private JMethod<F> {\n  using JMethod<F>::JMethod;\n private:\n  JConstructor(const JMethod<F>& other) : JMethod<F>(other.getId()) {}\n  friend class JClass;\n};\n\n/// Representation of a jStaticMethodID\ntemplate<typename F>\nclass JStaticMethod;\n\n/// @cond INTERNAL\n#pragma push_macro(\"DEFINE_PRIMITIVE_STATIC_METHOD_CLASS\")\n\n#undef DEFINE_PRIMITIVE_STATIC_METHOD_CLASS\n\n// Defining JStaticMethod specializations based on return value\n#define DEFINE_PRIMITIVE_STATIC_METHOD_CLASS(TYPE)                          \\\ntemplate<typename... Args>                                                  \\\nclass JStaticMethod<TYPE(Args...)> : public JMethodBase {                   \\\n  static_assert(std::is_void<TYPE>::value || IsJniPrimitive<TYPE>(),        \\\n      \"T must be a JNI primitive or void\");                                 \\\n                                                                            \\\n public:                                                                    \\\n  using JMethodBase::JMethodBase;                                           \\\n  JStaticMethod() noexcept {};                                              \\\n  JStaticMethod(const JStaticMethod& other) noexcept = default;             \\\n                                                                            \\\n  TYPE operator()(alias_ref<jclass> cls, Args... args);                     \\\n                                                                            \\\n  friend class JClass;                                                      \\\n}\n\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(void);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jboolean);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jbyte);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jchar);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jshort);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jint);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jlong);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jfloat);\nDEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jdouble);\n\n#pragma pop_macro(\"DEFINE_PRIMITIVE_STATIC_METHOD_CLASS\")\n/// @endcond\n\n\n/// Representation of a jNonvirtualMethodID\ntemplate<typename F>\nclass JNonvirtualMethod;\n\n/// @cond INTERNAL\n#pragma push_macro(\"DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS\")\n\n#undef DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS\n\n// Defining JNonvirtualMethod specializations based on return value\n#define DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(TYPE)                     \\\ntemplate<typename... Args>                                                  \\\nclass JNonvirtualMethod<TYPE(Args...)> : public JMethodBase {               \\\n  static_assert(std::is_void<TYPE>::value || IsJniPrimitive<TYPE>(),        \\\n      \"T must be a JNI primitive or void\");                                 \\\n                                                                            \\\n public:                                                                    \\\n  using JMethodBase::JMethodBase;                                           \\\n  JNonvirtualMethod() noexcept {};                                          \\\n  JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default;     \\\n                                                                            \\\n  TYPE operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args);       \\\n                                                                            \\\n  friend class JClass;                                                      \\\n}\n\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(void);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jboolean);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jbyte);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jchar);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jshort);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jint);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jlong);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jfloat);\nDEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jdouble);\n\n#pragma pop_macro(\"DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS\")\n/// @endcond\n\n\n/**\n * JField represents typed fields and simplifies their access. Note that object types return\n * raw pointers which generally should promptly get a wrap_local treatment.\n */\ntemplate<typename T>\nclass JField {\n  static_assert(IsJniScalar<T>(), \"T must be a JNI scalar\");\n\n public:\n  /// Wraps an existing field id\n  explicit JField(jfieldID field = nullptr) noexcept;\n\n  /// Verify that the id is valid\n  explicit operator bool() const noexcept;\n\n  /// Access the wrapped id\n  jfieldID getId() const noexcept;\n\n private:\n  jfieldID field_id_;\n\n  /// Get field value\n  /// @pre object != nullptr\n  T get(jobject object) const noexcept;\n\n  /// Set field value\n  /// @pre object != nullptr\n  void set(jobject object, T value) noexcept;\n\n  friend class JObject;\n};\n\n\n/**\n * JStaticField represents typed fields and simplifies their access. Note that object types\n * return raw pointers which generally should promptly get a wrap_local treatment.\n */\ntemplate<typename T>\nclass JStaticField {\n  static_assert(IsJniScalar<T>(), \"T must be a JNI scalar\");\n\n public:\n  /// Wraps an existing field id\n  explicit JStaticField(jfieldID field = nullptr) noexcept;\n\n  /// Verify that the id is valid\n  explicit operator bool() const noexcept;\n\n  /// Access the wrapped id\n  jfieldID getId() const noexcept;\n\n private:\n  jfieldID field_id_;\n\n  /// Get field value\n  /// @pre object != nullptr\n  T get(jclass jcls) const noexcept;\n\n  /// Set field value\n  /// @pre object != nullptr\n  void set(jclass jcls, T value) noexcept;\n\n  friend class JClass;\n  friend class JObject;\n};\n\n\n/// Template magic to provide @ref jmethod_traits\ntemplate<typename R, typename... Args>\nstruct jmethod_traits<R(Args...)> {\n  static std::string descriptor();\n  static std::string constructor_descriptor();\n};\n\n\n// jtype_traits ////////////////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T>\nstruct jtype_traits {\nprivate:\n  using Repr = ReprType<T>;\npublic:\n  // The jni type signature (described at\n  // http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html).\n  static std::string descriptor() {\n    std::string descriptor;\n    if (Repr::kJavaDescriptor == nullptr) {\n      descriptor = Repr::get_instantiated_java_descriptor();\n    } else {\n      descriptor = Repr::kJavaDescriptor;\n    }\n    return descriptor;\n  }\n\n  // The signature used for class lookups. See\n  // http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName().\n  static std::string base_name() {\n    if (Repr::kJavaDescriptor != nullptr) {\n      std::string base_name = Repr::kJavaDescriptor;\n      return base_name.substr(1, base_name.size() - 2);\n    }\n    return Repr::get_instantiated_base_name();\n  }\n};\n\n#pragma push_macro(\"DEFINE_FIELD_AND_ARRAY_TRAIT\")\n#undef DEFINE_FIELD_AND_ARRAY_TRAIT\n\n#define DEFINE_FIELD_AND_ARRAY_TRAIT(TYPE, DSC)                     \\\ntemplate<>                                                          \\\nstruct jtype_traits<TYPE> {                                         \\\n  static std::string descriptor() { return std::string{#DSC}; }     \\\n  static std::string base_name() { return descriptor(); }           \\\n  using array_type = TYPE ## Array;                                 \\\n};                                                                  \\\ntemplate<>                                                          \\\nstruct jtype_traits<TYPE ## Array> {                                \\\n  static std::string descriptor() { return std::string{\"[\" #DSC}; } \\\n  static std::string base_name() { return descriptor(); }           \\\n  using entry_type = TYPE;                                          \\\n};\n\n// There is no voidArray, handle that without the macro.\ntemplate<>\nstruct jtype_traits<void> {\n  static std::string descriptor() { return std::string{\"V\"}; };\n};\n\nDEFINE_FIELD_AND_ARRAY_TRAIT(jboolean, Z)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jbyte,    B)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jchar,    C)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jshort,   S)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jint,     I)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jlong,    J)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jfloat,   F)\nDEFINE_FIELD_AND_ARRAY_TRAIT(jdouble,  D)\n\n#pragma pop_macro(\"DEFINE_FIELD_AND_ARRAY_TRAIT\")\n\n\ntemplate <typename T>\nstruct jmethod_traits_from_cxx;\n\n}}\n\n#include \"Meta-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/MetaConvert.h",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#pragma once\n\n#include <jni.h>\n\n#include \"Common.h\"\n#include \"References.h\"\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\n// In order to avoid potentially filling the jni locals table,\n// temporary objects (right now, this is just jstrings) need to be\n// released. This is done by returning a holder which autoconverts to\n// jstring.\ntemplate <typename T>\ninline T callToJni(T&& t) {\n  return t;\n}\n\ntemplate <typename T>\ninline JniType<T> callToJni(local_ref<T>&& sref) {\n  return sref.get();\n}\n\n// Normally, pass through types unmolested.\ntemplate <typename T, typename Enabled = void>\nstruct Convert {\n  typedef T jniType;\n  static jniType fromJni(jniType t) {\n    return t;\n  }\n  static jniType toJniRet(jniType t) {\n    return t;\n  }\n  static jniType toCall(jniType t) {\n    return t;\n  }\n};\n\n// This is needed for return conversion\ntemplate <>\nstruct Convert<void> {\n  typedef void jniType;\n};\n\n// jboolean is an unsigned char, not a bool. Allow it to work either way.\ntemplate<>\nstruct Convert<bool> {\n  typedef jboolean jniType;\n  static bool fromJni(jniType t) {\n    return t;\n  }\n  static jniType toJniRet(bool t) {\n    return t;\n  }\n  static jniType toCall(bool t) {\n    return t;\n  }\n};\n\n// convert to alias_ref<T> from T\ntemplate <typename T>\nstruct Convert<alias_ref<T>> {\n  typedef JniType<T> jniType;\n  static alias_ref<jniType> fromJni(jniType t) {\n    return wrap_alias(t);\n  }\n  static jniType toJniRet(alias_ref<jniType> t) {\n    return t.get();\n  }\n  static jniType toCall(alias_ref<jniType> t) {\n    return t.get();\n  }\n};\n\n// convert return from local_ref<T>\ntemplate <typename T>\nstruct Convert<local_ref<T>> {\n  typedef JniType<T> jniType;\n  // No automatic synthesis of local_ref\n  static jniType toJniRet(local_ref<jniType> t) {\n    return t.release();\n  }\n  static jniType toCall(local_ref<jniType> t) {\n    return t.get();\n  }\n};\n\n// convert return from global_ref<T>\ntemplate <typename T>\nstruct Convert<global_ref<T>> {\n  typedef JniType<T> jniType;\n  // No automatic synthesis of global_ref\n  static jniType toJniRet(global_ref<jniType>&& t) {\n    // If this gets called, ownership the global_ref was passed in here.  (It's\n    // probably a copy of a persistent global_ref made when a function was\n    // declared to return a global_ref, but it could moved out or otherwise not\n    // referenced elsewhere.  Doesn't matter.)  Either way, the only safe way\n    // to return it is to make a local_ref, release it, and return the\n    // underlying local jobject.\n    auto ret = make_local(t);\n    return ret.release();\n  }\n  static jniType toJniRet(const global_ref<jniType>& t) {\n    // If this gets called, the function was declared to return const&.  We\n    // have a ref to a global_ref whose lifetime will exceed this call, so we\n    // can just get the underlying jobject and return it to java without\n    // needing to make a local_ref.\n    return t.get();\n  }\n  static jniType toCall(global_ref<jniType> t) {\n    return t.get();\n  }\n};\n\ntemplate <typename T> struct jni_sig_from_cxx_t;\ntemplate <typename R, typename... Args>\nstruct jni_sig_from_cxx_t<R(Args...)> {\n  using JniRet = typename Convert<typename std::decay<R>::type>::jniType;\n  using JniSig = JniRet(typename Convert<typename std::decay<Args>::type>::jniType...);\n};\n\ntemplate <typename T>\nusing jni_sig_from_cxx = typename jni_sig_from_cxx_t<T>::JniSig;\n\n} // namespace detail\n\ntemplate <typename R, typename... Args>\nstruct jmethod_traits_from_cxx<R(Args...)> : jmethod_traits<detail::jni_sig_from_cxx<R(Args...)>> {\n};\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/NativeRunnable.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"CoreClasses.h\"\n#include \"Hybrid.h\"\n#include \"Registration.h\"\n\n#include <functional>\n\nnamespace facebook {\nnamespace jni {\n\nstruct JRunnable : public JavaClass<JRunnable> {\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/Runnable;\";\n};\n\nstruct JNativeRunnable : public HybridClass<JNativeRunnable, JRunnable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/NativeRunnable;\";\n\n  JNativeRunnable(std::function<void()>&& runnable) : runnable_(std::move(runnable)) {}\n\n  static void OnLoad() {\n    registerHybrid({\n        makeNativeMethod(\"run\", JNativeRunnable::run),\n      });\n  }\n\n  void run() {\n    runnable_();\n  }\n\n private:\n  std::function<void()> runnable_;\n};\n\n\n} // namespace jni\n} // namespace facebook\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/ReferenceAllocators-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <cassert>\n#include <new>\n#include <atomic>\n\nnamespace facebook {\nnamespace jni {\n\n/// @cond INTERNAL\nnamespace internal {\n\n// Statistics mostly provided for test (only updated if FBJNI_DEBUG_REFS is defined)\nstruct ReferenceStats {\n  std::atomic_uint locals_created, globals_created, weaks_created,\n                   locals_deleted, globals_deleted, weaks_deleted;\n\n  void reset() noexcept;\n};\n\nextern ReferenceStats g_reference_stats;\n}\n/// @endcond\n\n\n// LocalReferenceAllocator /////////////////////////////////////////////////////////////////////////\n\ninline jobject LocalReferenceAllocator::newReference(jobject original) const {\n  internal::dbglog(\"Local new: %p\", original);\n  #ifdef FBJNI_DEBUG_REFS\n    ++internal::g_reference_stats.locals_created;\n  #endif\n  auto ref = internal::getEnv()->NewLocalRef(original);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  return ref;\n}\n\ninline void LocalReferenceAllocator::deleteReference(jobject reference) const noexcept {\n  internal::dbglog(\"Local release: %p\", reference);\n\n  if (reference) {\n    #ifdef FBJNI_DEBUG_REFS\n      ++internal::g_reference_stats.locals_deleted;\n    #endif\n    assert(verifyReference(reference));\n    internal::getEnv()->DeleteLocalRef(reference);\n  }\n}\n\ninline bool LocalReferenceAllocator::verifyReference(jobject reference) const noexcept {\n  if (!reference || !internal::doesGetObjectRefTypeWork()) {\n    return true;\n  }\n  return internal::getEnv()->GetObjectRefType(reference) == JNILocalRefType;\n}\n\n\n// GlobalReferenceAllocator ////////////////////////////////////////////////////////////////////////\n\ninline jobject GlobalReferenceAllocator::newReference(jobject original) const {\n  internal::dbglog(\"Global new: %p\", original);\n  #ifdef FBJNI_DEBUG_REFS\n    ++internal::g_reference_stats.globals_created;\n  #endif\n  auto ref = internal::getEnv()->NewGlobalRef(original);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  return ref;\n}\n\ninline void GlobalReferenceAllocator::deleteReference(jobject reference) const noexcept {\n  internal::dbglog(\"Global release: %p\", reference);\n\n  if (reference) {\n    #ifdef FBJNI_DEBUG_REFS\n      ++internal::g_reference_stats.globals_deleted;\n    #endif\n    assert(verifyReference(reference));\n    internal::getEnv()->DeleteGlobalRef(reference);\n  }\n}\n\ninline bool GlobalReferenceAllocator::verifyReference(jobject reference) const noexcept {\n  if (!reference || !internal::doesGetObjectRefTypeWork()) {\n    return true;\n  }\n  return internal::getEnv()->GetObjectRefType(reference) == JNIGlobalRefType;\n}\n\n\n// WeakGlobalReferenceAllocator ////////////////////////////////////////////////////////////////////\n\ninline jobject WeakGlobalReferenceAllocator::newReference(jobject original) const {\n  internal::dbglog(\"Weak global new: %p\", original);\n  #ifdef FBJNI_DEBUG_REFS\n    ++internal::g_reference_stats.weaks_created;\n  #endif\n  auto ref = internal::getEnv()->NewWeakGlobalRef(original);\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  return ref;\n}\n\ninline void WeakGlobalReferenceAllocator::deleteReference(jobject reference) const noexcept {\n  internal::dbglog(\"Weak Global release: %p\", reference);\n\n  if (reference) {\n    #ifdef FBJNI_DEBUG_REFS\n      ++internal::g_reference_stats.weaks_deleted;\n    #endif\n    assert(verifyReference(reference));\n    internal::getEnv()->DeleteWeakGlobalRef(reference);\n  }\n}\n\ninline bool WeakGlobalReferenceAllocator::verifyReference(jobject reference) const noexcept {\n  if (!reference || !internal::doesGetObjectRefTypeWork()) {\n    return true;\n  }\n  return internal::getEnv()->GetObjectRefType(reference) == JNIWeakGlobalRefType;\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/ReferenceAllocators.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n/**\n * @file ReferenceAllocators.h\n *\n * Reference allocators are used to create and delete various classes of JNI references (local,\n * global, and weak global).\n */\n\n#pragma once\n\n#include <fb/visibility.h>\n\n#include \"Common.h\"\n\nnamespace facebook { namespace jni {\n\n/// Allocator that handles local references\nclass FBEXPORT LocalReferenceAllocator {\n public:\n  jobject newReference(jobject original) const;\n  void deleteReference(jobject reference) const noexcept;\n  bool verifyReference(jobject reference) const noexcept;\n};\n\n/// Allocator that handles global references\nclass FBEXPORT GlobalReferenceAllocator {\n public:\n  jobject newReference(jobject original) const;\n  void deleteReference(jobject reference) const noexcept;\n  bool verifyReference(jobject reference) const noexcept;\n};\n\n/// Allocator that handles weak global references\nclass FBEXPORT WeakGlobalReferenceAllocator {\n public:\n  jobject newReference(jobject original) const;\n  void deleteReference(jobject reference) const noexcept;\n  bool verifyReference(jobject reference) const noexcept;\n};\n\n/// @cond INTERNAL\nnamespace internal {\n\n/**\n * @return true iff env->GetObjectRefType is expected to work properly.\n */\nFBEXPORT bool doesGetObjectRefTypeWork();\n\n}\n/// @endcond\n\n}}\n\n#include \"ReferenceAllocators-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/References-forward.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"ReferenceAllocators.h\"\n\nnamespace facebook {\nnamespace jni {\n\ntemplate<typename T, typename Enable = void>\nclass JObjectWrapper;\n\nnamespace detail {\nstruct JObjectBase {\n  jobject get() const noexcept;\n  void set(jobject reference) noexcept;\n  jobject this_;\n};\n\n// RefReprType maps a type to the representation used by fbjni smart references.\ntemplate <typename T, typename Enable = void>\nstruct RefReprType;\n\ntemplate <typename T>\nstruct JavaObjectType;\n\ntemplate <typename T>\nstruct ReprAccess;\n}\n\n// Given T, either a jobject-like type or a JavaClass-derived type, ReprType<T>\n// is the corresponding JavaClass-derived type and JniType<T> is the\n// jobject-like type.\ntemplate <typename T>\nusing ReprType = typename detail::RefReprType<T>::type;\n\ntemplate <typename T>\nusing JniType = typename detail::JavaObjectType<T>::type;\n\ntemplate<typename T, typename Alloc>\nclass base_owned_ref;\n\ntemplate<typename T, typename Alloc>\nclass basic_strong_ref;\n\ntemplate<typename T>\nclass weak_ref;\n\ntemplate<typename T>\nclass alias_ref;\n\n/// A smart unique reference owning a local JNI reference\ntemplate<typename T>\nusing local_ref = basic_strong_ref<T, LocalReferenceAllocator>;\n\n/// A smart unique reference owning a global JNI reference\ntemplate<typename T>\nusing global_ref = basic_strong_ref<T, GlobalReferenceAllocator>;\n\n}} // namespace facebook::jni\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/References-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <new>\n#include \"CoreClasses.h\"\n\nnamespace facebook {\nnamespace jni {\n\ntemplate<typename T>\ninline enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref) {\n  return ref;\n}\n\ntemplate<typename T>\ninline JniType<T> getPlainJniReference(alias_ref<T> ref) {\n  return ref.get();\n}\n\ntemplate<typename T, typename A>\ninline JniType<T> getPlainJniReference(const base_owned_ref<T, A>& ref) {\n  return ref.get();\n}\n\n\nnamespace detail {\ntemplate <typename Repr>\nstruct ReprAccess {\n  using javaobject = JniType<Repr>;\n  static void set(Repr& repr, javaobject obj) noexcept {\n    repr.JObjectBase::set(obj);\n  }\n  static javaobject get(const Repr& repr) {\n    return static_cast<javaobject>(repr.JObject::get());\n  }\n};\n\nnamespace {\ntemplate <typename Repr>\nvoid StaticAssertValidRepr() noexcept {\n  static_assert(std::is_base_of<JObject, Repr>::value,\n      \"A smart ref representation must be derived from JObject.\");\n  static_assert(IsPlainJniReference<JniType<Repr>>(), \"T must be a JNI reference\");\n  static_assert(sizeof(Repr) == sizeof(JObjectBase), \"\");\n  static_assert(alignof(Repr) == alignof(JObjectBase), \"\");\n}\n}\n\ntemplate <typename Repr>\nReprStorage<Repr>::ReprStorage(JniType<Repr> obj) noexcept {\n  StaticAssertValidRepr<Repr>();\n  set(obj);\n}\n\ntemplate <typename Repr>\nvoid ReprStorage<Repr>::set(JniType<Repr> obj) noexcept {\n  new (&storage_) Repr;\n  ReprAccess<Repr>::set(get(), obj);\n}\n\ntemplate <typename Repr>\nRepr& ReprStorage<Repr>::get() noexcept {\n  return *reinterpret_cast<Repr*>(&storage_);\n}\n\ntemplate <typename Repr>\nconst Repr& ReprStorage<Repr>::get() const noexcept {\n  return *reinterpret_cast<const Repr*>(&storage_);\n}\n\ntemplate <typename Repr>\nJniType<Repr> ReprStorage<Repr>::jobj() const noexcept {\n  ReprAccess<Repr>::get(get());\n  return ReprAccess<Repr>::get(get());\n}\n\ntemplate <typename Repr>\nvoid ReprStorage<Repr>::swap(ReprStorage& other) noexcept {\n  StaticAssertValidRepr<Repr>();\n  using std::swap;\n  swap(get(), other.get());\n}\n\ninline void JObjectBase::set(jobject reference) noexcept {\n  this_ = reference;\n}\n\ninline jobject JObjectBase::get() const noexcept {\n  return this_;\n}\n\ntemplate<typename T, typename Alloc>\nenable_if_t<IsNonWeakReference<T>(), plain_jni_reference_t<T>> make_ref(const T& reference) {\n  auto old_reference = getPlainJniReference(reference);\n  if (!old_reference) {\n    return nullptr;\n  }\n\n  auto ref = Alloc{}.newReference(old_reference);\n  if (!ref) {\n    // Note that we end up here if we pass a weak ref that refers to a collected object.\n    // Thus, it's hard to come up with a reason why this function should be used with\n    // weak references.\n    throw std::bad_alloc{};\n  }\n\n  return static_cast<plain_jni_reference_t<T>>(ref);\n}\n\n} // namespace detail\n\ntemplate<typename T>\ninline local_ref<T> adopt_local(T ref) noexcept {\n  static_assert(IsPlainJniReference<T>(), \"T must be a plain jni reference\");\n  return local_ref<T>{ref};\n}\n\ntemplate<typename T>\ninline global_ref<T> adopt_global(T ref) noexcept {\n  static_assert(IsPlainJniReference<T>(), \"T must be a plain jni reference\");\n  return global_ref<T>{ref};\n}\n\ntemplate<typename T>\ninline weak_ref<T> adopt_weak_global(T ref) noexcept {\n  static_assert(IsPlainJniReference<T>(), \"T must be a plain jni reference\");\n  return weak_ref<T>{ref};\n}\n\n\ntemplate<typename T>\ninline enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept {\n  return alias_ref<T>(ref);\n}\n\n\ntemplate<typename T>\nenable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;\n\n\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), local_ref<plain_jni_reference_t<T>>>\nmake_local(const T& ref) {\n  return adopt_local(detail::make_ref<T, LocalReferenceAllocator>(ref));\n}\n\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), global_ref<plain_jni_reference_t<T>>>\nmake_global(const T& ref) {\n  return adopt_global(detail::make_ref<T, GlobalReferenceAllocator>(ref));\n}\n\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), weak_ref<plain_jni_reference_t<T>>>\nmake_weak(const T& ref) {\n  return adopt_weak_global(detail::make_ref<T, WeakGlobalReferenceAllocator>(ref));\n}\n\ntemplate<typename T1, typename T2>\ninline enable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>\noperator==(const T1& a, const T2& b) {\n  return isSameObject(getPlainJniReference(a), getPlainJniReference(b));\n}\n\ntemplate<typename T1, typename T2>\ninline enable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>\noperator!=(const T1& a, const T2& b) {\n  return !(a == b);\n}\n\n\n// base_owned_ref ///////////////////////////////////////////////////////////////////////\n\ntemplate<typename T, typename Alloc>\ninline base_owned_ref<T, Alloc>::base_owned_ref() noexcept\n  : base_owned_ref(nullptr)\n{}\n\ntemplate<typename T, typename Alloc>\ninline base_owned_ref<T, Alloc>::base_owned_ref(std::nullptr_t t) noexcept\n  : base_owned_ref(static_cast<javaobject>(nullptr))\n{}\n\ntemplate<typename T, typename Alloc>\ninline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref& other)\n  : storage_{static_cast<javaobject>(Alloc{}.newReference(other.get()))}\n{}\n\ntemplate<typename T, typename Alloc>\ntemplate<typename U>\ninline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref<U, Alloc>& other)\n  : storage_{static_cast<javaobject>(Alloc{}.newReference(other.get()))}\n{\n  static_assert(std::is_convertible<JniType<U>, javaobject>::value, \"\");\n}\n\ntemplate<typename T, typename Alloc>\ninline facebook::jni::base_owned_ref<T, Alloc>::base_owned_ref(\n    javaobject reference) noexcept\n  : storage_(reference) {\n  assert(Alloc{}.verifyReference(reference));\n  internal::dbglog(\"New wrapped ref=%p this=%p\", get(), this);\n}\n\ntemplate<typename T, typename Alloc>\ninline base_owned_ref<T, Alloc>::base_owned_ref(\n    base_owned_ref<T, Alloc>&& other) noexcept\n  : storage_(other.get()) {\n  internal::dbglog(\"New move from ref=%p other=%p\", other.get(), &other);\n  internal::dbglog(\"New move to ref=%p this=%p\", get(), this);\n  // JObject is a simple type and does not support move semantics so we explicitly\n  // clear other\n  other.set(nullptr);\n}\n\ntemplate<typename T, typename Alloc>\ntemplate<typename U>\nbase_owned_ref<T, Alloc>::base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept\n  : storage_(other.get()) {\n  internal::dbglog(\"New move from ref=%p other=%p\", other.get(), &other);\n  internal::dbglog(\"New move to ref=%p this=%p\", get(), this);\n  // JObject is a simple type and does not support move semantics so we explicitly\n  // clear other\n  other.set(nullptr);\n}\n\ntemplate<typename T, typename Alloc>\ninline base_owned_ref<T, Alloc>::~base_owned_ref() noexcept {\n  reset();\n  internal::dbglog(\"Ref destruct ref=%p this=%p\", get(), this);\n}\n\ntemplate<typename T, typename Alloc>\ninline auto base_owned_ref<T, Alloc>::release() noexcept -> javaobject {\n  auto value = get();\n  internal::dbglog(\"Ref release ref=%p this=%p\", value, this);\n  set(nullptr);\n  return value;\n}\n\ntemplate<typename T, typename Alloc>\ninline void base_owned_ref<T,Alloc>::reset() noexcept {\n  reset(nullptr);\n}\n\ntemplate<typename T, typename Alloc>\ninline void base_owned_ref<T,Alloc>::reset(javaobject reference) noexcept {\n  if (get()) {\n    assert(Alloc{}.verifyReference(reference));\n    Alloc{}.deleteReference(get());\n  }\n  set(reference);\n}\n\ntemplate<typename T, typename Alloc>\ninline auto base_owned_ref<T, Alloc>::get() const noexcept -> javaobject {\n  return storage_.jobj();\n}\n\ntemplate<typename T, typename Alloc>\ninline void base_owned_ref<T, Alloc>::set(javaobject ref) noexcept {\n  storage_.set(ref);\n}\n\n\n// weak_ref ///////////////////////////////////////////////////////////////////////\n\ntemplate<typename T>\ninline weak_ref<T>& weak_ref<T>::operator=(\n    const weak_ref& other) {\n  auto otherCopy = other;\n  swap(*this, otherCopy);\n  return *this;\n}\n\ntemplate<typename T>\ninline weak_ref<T>& weak_ref<T>::operator=(\n    weak_ref<T>&& other) noexcept {\n  internal::dbglog(\"Op= move ref=%p this=%p oref=%p other=%p\",\n      get(), this, other.get(), &other);\n  reset(other.release());\n  return *this;\n}\n\ntemplate<typename T>\nlocal_ref<T> weak_ref<T>::lockLocal() const {\n  return adopt_local(\n      static_cast<javaobject>(LocalReferenceAllocator{}.newReference(get())));\n}\n\ntemplate<typename T>\nglobal_ref<T> weak_ref<T>::lockGlobal() const {\n  return adopt_global(\n      static_cast<javaobject>(GlobalReferenceAllocator{}.newReference(get())));\n}\n\ntemplate<typename T>\ninline void swap(\n    weak_ref<T>& a,\n    weak_ref<T>& b) noexcept {\n  internal::dbglog(\"Ref swap a.ref=%p a=%p b.ref=%p b=%p\",\n      a.get(), &a, b.get(), &b);\n  a.storage_.swap(b.storage_);\n}\n\n\n// basic_strong_ref ////////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T, typename Alloc>\ninline basic_strong_ref<T, Alloc>& basic_strong_ref<T, Alloc>::operator=(\n    const basic_strong_ref& other) {\n  auto otherCopy = other;\n  swap(*this, otherCopy);\n  return *this;\n}\n\ntemplate<typename T, typename Alloc>\ninline basic_strong_ref<T, Alloc>& basic_strong_ref<T, Alloc>::operator=(\n    basic_strong_ref<T, Alloc>&& other) noexcept {\n  internal::dbglog(\"Op= move ref=%p this=%p oref=%p other=%p\",\n      get(), this, other.get(), &other);\n  reset(other.release());\n  return *this;\n}\n\ntemplate<typename T, typename Alloc>\ninline alias_ref<T> basic_strong_ref<T, Alloc>::releaseAlias() noexcept {\n  return wrap_alias(release());\n}\n\ntemplate<typename T, typename Alloc>\ninline basic_strong_ref<T, Alloc>::operator bool() const noexcept {\n  return get() != nullptr;\n}\n\ntemplate<typename T, typename Alloc>\ninline auto basic_strong_ref<T, Alloc>::operator->() noexcept -> Repr* {\n  return &storage_.get();\n}\n\ntemplate<typename T, typename Alloc>\ninline auto basic_strong_ref<T, Alloc>::operator->() const noexcept -> const Repr* {\n  return &storage_.get();\n}\n\ntemplate<typename T, typename Alloc>\ninline auto basic_strong_ref<T, Alloc>::operator*() noexcept -> Repr& {\n  return storage_.get();\n}\n\ntemplate<typename T, typename Alloc>\ninline auto basic_strong_ref<T, Alloc>::operator*() const noexcept -> const Repr& {\n  return storage_.get();\n}\n\ntemplate<typename T, typename Alloc>\ninline void swap(\n    basic_strong_ref<T, Alloc>& a,\n    basic_strong_ref<T, Alloc>& b) noexcept {\n  internal::dbglog(\"Ref swap a.ref=%p a=%p b.ref=%p b=%p\",\n      a.get(), &a, b.get(), &b);\n  using std::swap;\n  a.storage_.swap(b.storage_);\n}\n\n\n// alias_ref //////////////////////////////////////////////////////////////////////////////\n\ntemplate<typename T>\ninline alias_ref<T>::alias_ref() noexcept\n  : storage_{nullptr}\n{}\n\ntemplate<typename T>\ninline alias_ref<T>::alias_ref(std::nullptr_t) noexcept\n  : storage_{nullptr}\n{}\n\ntemplate<typename T>\ninline alias_ref<T>::alias_ref(const alias_ref& other) noexcept\n  : storage_{other.get()}\n{}\n\ntemplate<typename T>\ninline alias_ref<T>::alias_ref(javaobject ref) noexcept\n  : storage_(ref) {\n  assert(\n      LocalReferenceAllocator{}.verifyReference(ref) ||\n      GlobalReferenceAllocator{}.verifyReference(ref));\n}\n\ntemplate<typename T>\ntemplate<typename TOther, typename /* for SFINAE */>\ninline alias_ref<T>::alias_ref(alias_ref<TOther> other) noexcept\n  : storage_{other.get()}\n{}\n\ntemplate<typename T>\ntemplate<typename TOther, typename AOther, typename /* for SFINAE */>\ninline alias_ref<T>::alias_ref(const basic_strong_ref<TOther, AOther>& other) noexcept\n  : storage_{other.get()}\n{}\n\ntemplate<typename T>\ninline alias_ref<T>& alias_ref<T>::operator=(alias_ref other) noexcept {\n  swap(*this, other);\n  return *this;\n}\n\ntemplate<typename T>\ninline alias_ref<T>::operator bool() const noexcept {\n  return get() != nullptr;\n}\n\ntemplate<typename T>\ninline auto facebook::jni::alias_ref<T>::get() const noexcept -> javaobject {\n  return storage_.jobj();\n}\n\ntemplate<typename T>\ninline auto alias_ref<T>::operator->() noexcept -> Repr* {\n  return &(**this);\n}\n\ntemplate<typename T>\ninline auto alias_ref<T>::operator->() const noexcept -> const Repr* {\n  return &(**this);\n}\n\ntemplate<typename T>\ninline auto alias_ref<T>::operator*() noexcept -> Repr& {\n  return storage_.get();\n}\n\ntemplate<typename T>\ninline auto alias_ref<T>::operator*() const noexcept -> const Repr& {\n  return storage_.get();\n}\n\ntemplate<typename T>\ninline void alias_ref<T>::set(javaobject ref) noexcept {\n  storage_.set(ref);\n}\n\ntemplate<typename T>\ninline void swap(alias_ref<T>& a, alias_ref<T>& b) noexcept {\n  a.storage_.swap(b.storage_);\n}\n\n// Could reduce code duplication by using a pointer-to-function\n// template argument.  I'm not sure whether that would make the code\n// more maintainable (DRY), or less (too clever/confusing.).\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), local_ref<T>>\nstatic_ref_cast(const local_ref<U>& ref) noexcept\n{\n  T p = static_cast<T>(ref.get());\n  return make_local(p);\n}\n\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), global_ref<T>>\nstatic_ref_cast(const global_ref<U>& ref) noexcept\n{\n  T p = static_cast<T>(ref.get());\n  return make_global(p);\n}\n\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), alias_ref<T>>\nstatic_ref_cast(const alias_ref<U>& ref) noexcept\n{\n  T p = static_cast<T>(ref.get());\n  return wrap_alias(p);\n}\n\ntemplate<typename T, typename RefType>\nauto dynamic_ref_cast(const RefType& ref) ->\nenable_if_t<IsPlainJniReference<T>(), decltype(static_ref_cast<T>(ref))>\n{\n  if (!ref) {\n    return decltype(static_ref_cast<T>(ref))();\n  }\n\n  static alias_ref<jclass> target_class = findClassStatic(jtype_traits<T>::base_name().c_str());\n  if (!target_class) {\n    throwNewJavaException(\"java/lang/ClassCastException\",\n                          \"Could not find class %s.\",\n                          jtype_traits<T>::base_name().c_str());\n\n  }\n\n  local_ref<jclass> source_class = ref->getClass();\n\n  if (!target_class->isAssignableFrom(source_class)) {\n    throwNewJavaException(\"java/lang/ClassCastException\",\n                          \"Tried to cast from %s to %s.\",\n                          source_class->toString().c_str(),\n                          jtype_traits<T>::base_name().c_str());\n  }\n\n  return static_ref_cast<T>(ref);\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/References.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n\n/** @file References.h\n *\n * Functionality similar to smart pointers, but for references into the VM. Four main reference\n * types are provided: local_ref, global_ref, weak_ref, and alias_ref. All are generic\n * templates that and refer to objects in the jobject hierarchy. The type of the referred objects\n * are specified using the template parameter. All reference types except alias_ref own their\n * underlying reference, just as a std smart pointer owns the underlying raw pointer. In the context\n * of std smart pointers, these references behave like unique_ptr, and have basically the same\n * interface. Thus, when the reference is destructed, the plain JNI reference, i.e. the underlying\n * JNI reference (like the parameters passed directly to JNI functions), is released. The alias\n * references provides no ownership and is a simple wrapper for plain JNI references.\n *\n * All but the weak references provides access to the underlying object using dereferencing, and a\n * get() method. It is also possible to convert these references to booleans to test for nullity.\n * To access the underlying object of a weak reference, the reference must either be released, or\n * the weak reference can be used to create a local or global reference.\n *\n * An owning reference is created either by moving the reference from an existing owned reference,\n * by copying an existing owned reference (which creates a new underlying reference), by using the\n * default constructor which initialize the reference to nullptr, or by using a helper function. The\n * helper function exist in two flavors: make_XXX or adopt_XXX.\n *\n * Adopting takes a plain JNI reference and wrap it in an owned reference. It takes ownership of the\n * plain JNI reference so be sure that no one else owns the reference when you adopt it, and make\n * sure that you know what kind of reference it is.\n *\n * New owned references can be created from existing plain JNI references, alias references, local\n * references, and global references (i.e. non-weak references) using the make_local, make_global,\n * and make_weak functions.\n *\n * Alias references can be implicitly initialized using global, local and plain JNI references using\n * the wrap_alias function. Here, we don't assume ownership of the passed-in reference, but rather\n * create a separate reference that we do own, leaving the passed-in reference to its fate.\n *\n * Similar rules apply for assignment. An owned reference can be copy or move assigned using a smart\n * reference of the same type. In the case of copy assignment a new reference is created. Alias\n * reference can also be assigned new values, but since they are simple wrappers of plain JNI\n * references there is no move semantics involved.\n *\n * Alias references are special in that they do not own the object and can therefore safely be\n * converted to and from its corresponding plain JNI reference. They are useful as parameters of\n * functions that do not affect the lifetime of a reference. Usage can be compared with using plain\n * JNI pointers as parameters where a function does not take ownership of the underlying object.\n *\n * The local, global, and alias references makes it possible to access methods in the underlying\n * objects. A core set of classes are implemented in CoreClasses.h, and user defined wrappers are\n * supported (see example below). The wrappers also supports inheritance so a wrapper can inherit\n * from another wrapper to gain access to its functionality. As an example the jstring wrapper\n * inherits from the jobject wrapper, so does the jclass wrapper. That means that you can for\n * example call the toString() method using the jclass wrapper, or any other class that inherits\n * from the jobject wrapper.\n *\n * Note that the wrappers are parameterized on the static type of your (jobject) pointer, thus if\n * you have a jobject that refers to a Java String you will need to cast it to jstring to get the\n * jstring wrapper. This also mean that if you make a down cast that is invalid there will be no one\n * stopping you and the wrappers currently does not detect this which can cause crashes. Thus, cast\n * wisely.\n *\n * @include WrapperSample.cpp\n */\n\n#pragma once\n\n#include <cassert>\n#include <cstddef>\n#include <type_traits>\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n\n#include \"ReferenceAllocators.h\"\n#include \"TypeTraits.h\"\n#include \"References-forward.h\"\n\nnamespace facebook {\nnamespace jni {\n\n/// Convenience function to wrap an existing local reference\ntemplate<typename T>\nlocal_ref<T> adopt_local(T ref) noexcept;\n\n/// Convenience function to wrap an existing global reference\ntemplate<typename T>\nglobal_ref<T> adopt_global(T ref) noexcept;\n\n/// Convenience function to wrap an existing weak reference\ntemplate<typename T>\nweak_ref<T> adopt_weak_global(T ref) noexcept;\n\n\n/// Swaps two owning references of the same type\ntemplate<typename T>\nvoid swap(weak_ref<T>& a, weak_ref<T>& b) noexcept;\n\n/// Swaps two owning references of the same type\ntemplate<typename T, typename Alloc>\nvoid swap(basic_strong_ref<T, Alloc>& a, basic_strong_ref<T, Alloc>& b) noexcept;\n\n/**\n * Retrieve the plain reference from a plain reference.\n */\ntemplate<typename T>\nenable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref);\n\n/**\n * Retrieve the plain reference from an alias reference.\n */\ntemplate<typename T>\nJniType<T> getPlainJniReference(alias_ref<T> ref);\n\n/**\n * Retrieve the plain JNI reference from any reference owned reference.\n */\ntemplate<typename T, typename Alloc>\nJniType<T> getPlainJniReference(const base_owned_ref<T, Alloc>& ref);\n\nclass JObject;\nclass JClass;\n\nnamespace detail {\n\ntemplate <typename T, typename Enable = void>\nstruct HasJniRefRepr : std::false_type {};\n\ntemplate <typename T>\nstruct HasJniRefRepr<T, typename std::enable_if<!std::is_same<typename T::JniRefRepr, void>::value, void>::type> : std::true_type {\n  using type = typename T::JniRefRepr;\n};\n\ntemplate <typename T>\nstruct RefReprType<T*> {\n  using type = typename std::conditional<HasJniRefRepr<T>::value, typename HasJniRefRepr<T>::type, JObjectWrapper<T*>>::type;\n  static_assert(std::is_base_of<JObject, type>::value,\n      \"Repr type missing JObject base.\");\n  static_assert(std::is_same<type, typename RefReprType<type>::type>::value,\n      \"RefReprType<T> not idempotent\");\n};\n\ntemplate <typename T>\nstruct RefReprType<T, typename std::enable_if<std::is_base_of<JObject, T>::value, void>::type> {\n  using type = T;\n  static_assert(std::is_base_of<JObject, type>::value,\n      \"Repr type missing JObject base.\");\n  static_assert(std::is_same<type, typename RefReprType<type>::type>::value,\n      \"RefReprType<T> not idempotent\");\n};\n\ntemplate <typename T>\nstruct JavaObjectType {\n  using type = typename RefReprType<T>::type::javaobject;\n  static_assert(IsPlainJniReference<type>(),\n      \"JavaObjectType<T> not a plain jni reference\");\n  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,\n      \"JavaObjectType<T> not idempotent\");\n};\n\ntemplate <typename T>\nstruct JavaObjectType<JObjectWrapper<T>> {\n  using type = T;\n  static_assert(IsPlainJniReference<type>(),\n      \"JavaObjectType<T> not a plain jni reference\");\n  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,\n      \"JavaObjectType<T> not idempotent\");\n};\n\ntemplate <typename T>\nstruct JavaObjectType<T*> {\n  using type = T*;\n  static_assert(IsPlainJniReference<type>(),\n      \"JavaObjectType<T> not a plain jni reference\");\n  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,\n      \"JavaObjectType<T> not idempotent\");\n};\n\ntemplate <typename Repr>\nstruct ReprStorage {\n  explicit ReprStorage(JniType<Repr> obj) noexcept;\n\n  void set(JniType<Repr> obj) noexcept;\n\n  Repr& get() noexcept;\n  const Repr& get() const noexcept;\n  JniType<Repr> jobj() const noexcept;\n\n  void swap(ReprStorage& other) noexcept;\n private:\n  ReprStorage() = delete;\n  ReprStorage(const ReprStorage&) = delete;\n  ReprStorage(ReprStorage&&) = delete;\n  ReprStorage& operator=(const ReprStorage&) = delete;\n  ReprStorage& operator=(ReprStorage&&) = delete;\n\n  using Storage = typename std::aligned_storage<sizeof(JObjectBase), alignof(JObjectBase)>::type;\n  Storage storage_;\n};\n\n} // namespace detail\n\n/**\n * Create a new local reference from an existing reference\n *\n * @param ref a plain JNI, alias, or strong reference\n * @return an owned local reference (referring to null if the input does)\n * @throws std::bad_alloc if the JNI reference could not be created\n */\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), local_ref<plain_jni_reference_t<T>>>\nmake_local(const T& r);\n\n/**\n * Create a new global reference from an existing reference\n *\n * @param ref a plain JNI, alias, or strong reference\n * @return an owned global reference (referring to null if the input does)\n * @throws std::bad_alloc if the JNI reference could not be created\n */\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), global_ref<plain_jni_reference_t<T>>>\nmake_global(const T& r);\n\n/**\n * Create a new weak global reference from an existing reference\n *\n * @param ref a plain JNI, alias, or strong reference\n * @return an owned weak global reference (referring to null if the input does)\n * @throws std::bad_alloc if the returned reference is null\n */\ntemplate<typename T>\nenable_if_t<IsNonWeakReference<T>(), weak_ref<plain_jni_reference_t<T>>>\nmake_weak(const T& r);\n\n/**\n * Compare two references to see if they refer to the same object\n */\ntemplate<typename T1, typename T2>\nenable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>\noperator==(const T1& a, const T2& b);\n\n/**\n * Compare two references to see if they don't refer to the same object\n */\ntemplate<typename T1, typename T2>\nenable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>\noperator!=(const T1& a, const T2& b);\n\ntemplate<typename T, typename Alloc>\nclass base_owned_ref {\n public:\n  using javaobject = JniType<T>;\n\n  /**\n   * Release the ownership and set the reference to null. Thus no deleter is invoked.\n   * @return Returns the reference\n   */\n  javaobject release() noexcept;\n\n  /**\n   * Reset the reference to refer to nullptr.\n   */\n  void reset() noexcept;\n\n protected:\n  using Repr = ReprType<T>;\n  detail::ReprStorage<Repr> storage_;\n\n  javaobject get() const noexcept;\n  void set(javaobject ref) noexcept;\n\n  /*\n   * Wrap an existing reference and transfers its ownership to the newly created unique reference.\n   * NB! Does not create a new reference\n   */\n  explicit base_owned_ref(javaobject reference) noexcept;\n\n  /// Create a null reference\n  base_owned_ref() noexcept;\n\n  /// Create a null reference\n  explicit base_owned_ref(std::nullptr_t) noexcept;\n\n  /// Copy constructor (note creates a new reference)\n  base_owned_ref(const base_owned_ref& other);\n  template<typename U>\n  base_owned_ref(const base_owned_ref<U, Alloc>& other);\n\n  /// Transfers ownership of an underlying reference from one unique reference to another\n  base_owned_ref(base_owned_ref&& other) noexcept;\n  template<typename U>\n  base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept;\n\n  /// The delete the underlying reference if applicable\n  ~base_owned_ref() noexcept;\n\n\n  /// Assignment operator (note creates a new reference)\n  base_owned_ref& operator=(const base_owned_ref& other);\n\n  /// Assignment by moving a reference thus not creating a new reference\n  base_owned_ref& operator=(base_owned_ref&& rhs) noexcept;\n\n  void reset(javaobject reference) noexcept;\n\n  friend javaobject jni::getPlainJniReference<>(const base_owned_ref& ref);\n\n  template<typename U, typename UAlloc>\n  friend class base_owned_ref;\n};\n\n\n/**\n * A smart reference that owns its underlying JNI reference. The class provides basic\n * functionality to handle a reference but gives no access to it unless the reference is\n * released, thus no longer owned. The API is stolen with pride from unique_ptr and the\n * semantics should be basically the same. This class should not be used directly, instead use\n * @ref weak_ref\n */\ntemplate<typename T>\nclass weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {\n public:\n  using javaobject = JniType<T>;\n\n  using Allocator = WeakGlobalReferenceAllocator;\n\n  // This inherits non-default, non-copy, non-move ctors.\n  using base_owned_ref<T, Allocator>::base_owned_ref;\n\n  /// Create a null reference\n  weak_ref() noexcept\n    : base_owned_ref<T, Allocator>{} {}\n\n  /// Create a null reference\n  /* implicit */ weak_ref(std::nullptr_t) noexcept\n    : base_owned_ref<T, Allocator>{nullptr} {}\n\n  /// Copy constructor (note creates a new reference)\n  weak_ref(const weak_ref& other)\n    : base_owned_ref<T, Allocator>{other} {}\n\n  // This needs to be explicit to change its visibility.\n  template<typename U>\n  weak_ref(const weak_ref<U>& other)\n    : base_owned_ref<T, Allocator>{other} {}\n\n  /// Transfers ownership of an underlying reference from one unique reference to another\n  weak_ref(weak_ref&& other) noexcept\n    : base_owned_ref<T, Allocator>{std::move(other)} {}\n\n\n  /// Assignment operator (note creates a new reference)\n  weak_ref& operator=(const weak_ref& other);\n\n  /// Assignment by moving a reference thus not creating a new reference\n  weak_ref& operator=(weak_ref&& rhs) noexcept;\n\n  // Creates an owned local reference to the referred object or to null if the object is reclaimed\n  local_ref<T> lockLocal() const;\n\n  // Creates an owned global reference to the referred object or to null if the object is reclaimed\n  global_ref<T> lockGlobal() const;\n\n private:\n  // get/release/reset on weak_ref are not exposed to users.\n  using base_owned_ref<T, Allocator>::get;\n  using base_owned_ref<T, Allocator>::release;\n  using base_owned_ref<T, Allocator>::reset;\n  /*\n   * Wrap an existing reference and transfers its ownership to the newly created unique reference.\n   * NB! Does not create a new reference\n   */\n  explicit weak_ref(javaobject reference) noexcept\n    : base_owned_ref<T, Allocator>{reference} {}\n\n  template<typename T2> friend class weak_ref;\n  friend weak_ref<javaobject> adopt_weak_global<javaobject>(javaobject ref) noexcept;\n  friend void swap<T>(weak_ref& a, weak_ref& b) noexcept;\n};\n\n\n/**\n * A class representing owned strong references to Java objects. This class\n * should not be used directly, instead use @ref local_ref, or @ref global_ref.\n */\ntemplate<typename T, typename Alloc>\nclass basic_strong_ref : public base_owned_ref<T, Alloc> {\n  using typename base_owned_ref<T, Alloc>::Repr;\n public:\n  using javaobject = JniType<T>;\n\n  using Allocator = Alloc;\n\n  // This inherits non-default, non-copy, non-move ctors.\n  using base_owned_ref<T, Alloc>::base_owned_ref;\n  using base_owned_ref<T, Alloc>::release;\n  using base_owned_ref<T, Alloc>::reset;\n\n  /// Create a null reference\n  basic_strong_ref() noexcept\n    : base_owned_ref<T, Alloc>{} {}\n\n  /// Create a null reference\n  /* implicit */ basic_strong_ref(std::nullptr_t) noexcept\n    : base_owned_ref<T, Alloc>{nullptr} {}\n\n  /// Copy constructor (note creates a new reference)\n  basic_strong_ref(const basic_strong_ref& other)\n    : base_owned_ref<T, Alloc>{other} {}\n\n  // This needs to be explicit to change its visibility.\n  template<typename U>\n  basic_strong_ref(const basic_strong_ref<U, Alloc>& other)\n    : base_owned_ref<T, Alloc>{other} {}\n\n  /// Transfers ownership of an underlying reference from one unique reference to another\n  basic_strong_ref(basic_strong_ref&& other) noexcept\n    : base_owned_ref<T, Alloc>{std::move(other)} {}\n\n  /// Assignment operator (note creates a new reference)\n  basic_strong_ref& operator=(const basic_strong_ref& other);\n\n  /// Assignment by moving a reference thus not creating a new reference\n  basic_strong_ref& operator=(basic_strong_ref&& rhs) noexcept;\n\n  /// Get the plain JNI reference\n  using base_owned_ref<T, Allocator>::get;\n\n  /// Release the ownership of the reference and return the wrapped reference in an alias\n  alias_ref<T> releaseAlias() noexcept;\n\n  /// Checks if the reference points to a non-null object\n  explicit operator bool() const noexcept;\n\n  /// Access the functionality provided by the object wrappers\n  Repr* operator->() noexcept;\n\n  /// Access the functionality provided by the object wrappers\n  const Repr* operator->() const noexcept;\n\n  /// Provide a reference to the underlying wrapper (be sure that it is non-null before invoking)\n  Repr& operator*() noexcept;\n\n  /// Provide a const reference to the underlying wrapper (be sure that it is non-null\n  /// before invoking)\n  const Repr& operator*() const noexcept;\n\n private:\n\n  using base_owned_ref<T, Alloc>::storage_;\n\n  /*\n   * Wrap an existing reference and transfers its ownership to the newly created unique reference.\n   * NB! Does not create a new reference\n   */\n  explicit basic_strong_ref(javaobject reference) noexcept\n    : base_owned_ref<T, Alloc>{reference} {}\n\n\n  friend local_ref<T> adopt_local<T>(T ref) noexcept;\n  friend global_ref<T> adopt_global<T>(T ref) noexcept;\n  friend void swap<T, Alloc>(basic_strong_ref& a, basic_strong_ref& b) noexcept;\n};\n\n\ntemplate<typename T>\nenable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;\n\n/// Swaps to alias reference of the same type\ntemplate<typename T>\nvoid swap(alias_ref<T>& a, alias_ref<T>& b) noexcept;\n\n/**\n * A non-owning variant of the smart references (a dumb reference). These references still provide\n * access to the functionality of the @ref JObjectWrapper specializations including exception\n * handling and ease of use. Use this representation when you don't want to claim ownership of the\n * underlying reference (compare to using raw pointers instead of smart pointers.) For symmetry use\n * @ref alias_ref instead of this class.\n */\ntemplate<typename T>\nclass alias_ref {\n  using Repr = ReprType<T>;\n\n public:\n  using javaobject = JniType<T>;\n\n  /// Create a null reference\n  alias_ref() noexcept;\n\n  /// Create a null reference\n  /* implicit */ alias_ref(std::nullptr_t) noexcept;\n\n  /// Copy constructor\n  alias_ref(const alias_ref& other) noexcept;\n\n  /// Wrap an existing plain JNI reference\n  /* implicit */ alias_ref(javaobject ref) noexcept;\n\n  /// Wrap an existing smart reference of any type convertible to T\n  template<\n    typename TOther,\n    typename = enable_if_t<\n      IsConvertible<JniType<TOther>, javaobject>(), T>\n    >\n  alias_ref(alias_ref<TOther> other) noexcept;\n\n  /// Wrap an existing alias reference of a type convertible to T\n  template<\n    typename TOther,\n    typename AOther,\n    typename = enable_if_t<\n      IsConvertible<JniType<TOther>, javaobject>(), T>\n    >\n  alias_ref(const basic_strong_ref<TOther, AOther>& other) noexcept;\n\n  /// Assignment operator\n  alias_ref& operator=(alias_ref other) noexcept;\n\n  /// Checks if the reference points to a non-null object\n  explicit operator bool() const noexcept;\n\n  /// Converts back to a plain JNI reference\n  javaobject get() const noexcept;\n\n  /// Access the functionality provided by the object wrappers\n  Repr* operator->() noexcept;\n\n  /// Access the functionality provided by the object wrappers\n  const Repr* operator->() const noexcept;\n\n  /// Provide a guaranteed non-null reference (be sure that it is non-null before invoking)\n  Repr& operator*() noexcept;\n\n  /// Provide a guaranteed non-null reference (be sure that it is non-null before invoking)\n  const Repr& operator*() const noexcept;\n\n private:\n  void set(javaobject ref) noexcept;\n\n  detail::ReprStorage<Repr> storage_;\n\n  friend void swap<T>(alias_ref& a, alias_ref& b) noexcept;\n};\n\n\n/**\n * RAII object to create a local JNI frame, using PushLocalFrame/PopLocalFrame.\n *\n * This is useful when you have a call which is initiated from C++-land, and therefore\n * doesn't automatically get a local JNI frame managed for you by the JNI framework.\n */\nclass FBEXPORT JniLocalScope {\npublic:\n  JniLocalScope(JNIEnv* p_env, jint capacity);\n  ~JniLocalScope();\n\nprivate:\n  JNIEnv* env_;\n  bool hasFrame_;\n};\n\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), local_ref<T>>\nstatic_ref_cast(const local_ref<U>& ref) noexcept;\n\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), global_ref<T>>\nstatic_ref_cast(const global_ref<U>& ref) noexcept;\n\ntemplate<typename T, typename U>\nenable_if_t<IsPlainJniReference<T>(), alias_ref<T>>\nstatic_ref_cast(const alias_ref<U>& ref) noexcept;\n\ntemplate<typename T, typename RefType>\nauto dynamic_ref_cast(const RefType& ref) ->\nenable_if_t<IsPlainJniReference<T>(), decltype(static_ref_cast<T>(ref))> ;\n\n}}\n\n#include \"References-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Registration-inl.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include \"Exceptions.h\"\n#include \"Hybrid.h\"\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\n#ifdef __i386__\n// X86 ABI forces 16 byte stack allignment on calls. Unfortunately\n// sometimes Dalvik chooses not to obey the ABI:\n// - https://code.google.com/p/android/issues/detail?id=61012\n// - https://android.googlesource.com/platform/ndk/+/81696d2%5E!/\n// Therefore, we tell the compiler to re-align the stack on entry\n// to our JNI functions.\n#define JNI_ENTRY_POINT __attribute__((force_align_arg_pointer))\n#else\n#define JNI_ENTRY_POINT\n#endif\n\ntemplate <typename R>\nstruct CreateDefault {\n  static R create() {\n    return R{};\n  }\n};\n\ntemplate <>\nstruct CreateDefault<void> {\n  static void create() {}\n};\n\ntemplate <typename R>\nusing Converter = Convert<typename std::decay<R>::type>;\n\ntemplate <typename F, F func, typename R, typename... Args>\nstruct WrapForVoidReturn {\n  static typename Converter<R>::jniType call(Args&&... args) {\n    return Converter<R>::toJniRet(func(std::forward<Args>(args)...));\n  }\n};\n\ntemplate <typename F, F func, typename... Args>\nstruct WrapForVoidReturn<F, func, void, Args...> {\n  static void call(Args&&... args) {\n    func(std::forward<Args>(args)...);\n  }\n};\n\n// registration wrapper for legacy JNI-style functions\ntemplate<typename F, F func, typename C, typename R, typename... Args>\nstruct BareJniWrapper {\n  JNI_ENTRY_POINT static R call(JNIEnv* env, jobject obj, Args... args) {\n    ThreadScope ts(env, internal::CacheEnvTag{});\n    try {\n      return (*func)(env, static_cast<JniType<C>>(obj), args...);\n    } catch (...) {\n      translatePendingCppExceptionToJavaException();\n      return CreateDefault<R>::create();\n    }\n  }\n};\n\n// registration wrappers for functions, with autoconversion of arguments.\ntemplate<typename F, F func, typename C, typename R, typename... Args>\nstruct FunctionWrapper {\n  using jniRet = typename Converter<R>::jniType;\n  JNI_ENTRY_POINT static jniRet call(JNIEnv* env, jobject obj, typename Converter<Args>::jniType... args) {\n    ThreadScope ts(env, internal::CacheEnvTag{});\n    try {\n      return WrapForVoidReturn<F, func, R, JniType<C>, Args...>::call(\n          static_cast<JniType<C>>(obj), Converter<Args>::fromJni(args)...);\n    } catch (...) {\n      translatePendingCppExceptionToJavaException();\n      return CreateDefault<jniRet>::create();\n    }\n  }\n};\n\n// registration wrappers for non-static methods, with autoconvertion of arguments.\ntemplate<typename M, M method, typename C, typename R, typename... Args>\nstruct MethodWrapper {\n  using jhybrid = typename C::jhybridobject;\n  static R dispatch(alias_ref<jhybrid> ref, Args&&... args) {\n    try {\n      // This is usually a noop, but if the hybrid object is a\n      // base class of other classes which register JNI methods,\n      // this will get the right type for the registered method.\n      auto cobj = static_cast<C*>(ref->cthis());\n      return (cobj->*method)(std::forward<Args>(args)...);\n    } catch (const std::exception& ex) {\n      C::mapException(ex);\n      throw;\n    }\n  }\n\n  JNI_ENTRY_POINT static typename Converter<R>::jniType call(\n      JNIEnv* env, jobject obj, typename Converter<Args>::jniType... args) {\n    return FunctionWrapper<R(*)(alias_ref<jhybrid>, Args&&...), dispatch, jhybrid, R, Args...>::call(env, obj, args...);\n  }\n};\n\ntemplate<typename F, F func, typename C, typename R, typename... Args>\ninline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) {\n  // This intentionally erases the real type; JNI will do it anyway\n  return reinterpret_cast<NativeMethodWrapper*>(&(BareJniWrapper<F, func, C, R, Args...>::call));\n}\n\ntemplate<typename F, F func, typename C, typename R, typename... Args>\ninline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref<C>, Args... args)) {\n  // This intentionally erases the real type; JNI will do it anyway\n  return reinterpret_cast<NativeMethodWrapper*>(&(FunctionWrapper<F, func, C, R, Args...>::call));\n}\n\ntemplate<typename M, M method, typename C, typename R, typename... Args>\ninline NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)) {\n  // This intentionally erases the real type; JNI will do it anyway\n  return reinterpret_cast<NativeMethodWrapper*>(&(MethodWrapper<M, method, C, R, Args...>::call));\n}\n\ntemplate<typename R, typename C, typename... Args>\ninline std::string makeDescriptor(R (*)(JNIEnv*, C, Args... args)) {\n  return jmethod_traits<R(Args...)>::descriptor();\n}\n\ntemplate<typename R, typename C, typename... Args>\ninline std::string makeDescriptor(R (*)(alias_ref<C>, Args... args)) {\n  return jmethod_traits_from_cxx<R(Args...)>::descriptor();\n}\n\ntemplate<typename R, typename C, typename... Args>\ninline std::string makeDescriptor(R (C::*)(Args... args)) {\n  return jmethod_traits_from_cxx<R(Args...)>::descriptor();\n}\n\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/Registration.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <jni.h>\n#include \"References.h\"\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\n// This uses the real JNI function as a non-type template parameter to\n// cause a (static member) function to exist with the same signature,\n// but with try/catch exception translation.\ntemplate<typename F, F func, typename C, typename R, typename... Args>\nNativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(JNIEnv*, jobject, Args... args));\n\n// Automatically wrap object argument, and don't take env explicitly.\ntemplate<typename F, F func, typename C, typename R, typename... Args>\nNativeMethodWrapper* exceptionWrapJNIMethod(R (*func0)(alias_ref<C>, Args... args));\n\n// Extract C++ instance from object, and invoke given method on it,\ntemplate<typename M, M method, typename C, typename R, typename... Args>\nNativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args));\n\n// This uses deduction to figure out the descriptor name if the types\n// are primitive or have JObjectWrapper specializations.\ntemplate<typename R, typename C, typename... Args>\nstd::string makeDescriptor(R (*func)(JNIEnv*, C, Args... args));\n\n// This uses deduction to figure out the descriptor name if the types\n// are primitive or have JObjectWrapper specializations.\ntemplate<typename R, typename C, typename... Args>\nstd::string makeDescriptor(R (*func)(alias_ref<C>, Args... args));\n\n// This uses deduction to figure out the descriptor name if the types\n// are primitive or have JObjectWrapper specializations.\ntemplate<typename R, typename C, typename... Args>\nstd::string makeDescriptor(R (C::*method0)(Args... args));\n\n}\n\n// We have to use macros here, because the func needs to be used\n// as both a decltype expression argument and as a non-type template\n// parameter, since C++ provides no way for translateException\n// to deduce the type of its non-type template parameter.\n// The empty string in the macros below ensures that name\n// is always a string literal (because that syntax is only\n// valid when name is a string literal).\n#define makeNativeMethod2(name, func)                                   \\\n  { name \"\", ::facebook::jni::detail::makeDescriptor(&func),            \\\n      ::facebook::jni::detail::exceptionWrapJNIMethod<decltype(&func), &func>(&func) }\n\n#define makeNativeMethod3(name, desc, func)                             \\\n  { name \"\", desc,                                                      \\\n      ::facebook::jni::detail::exceptionWrapJNIMethod<decltype(&func), &func>(&func) }\n\n// Variadic template hacks to get macros with different numbers of\n// arguments. Usage instructions are in CoreClasses.h.\n#define makeNativeMethodN(a, b, c, count, ...) makeNativeMethod ## count\n#define makeNativeMethod(...) makeNativeMethodN(__VA_ARGS__, 3, 2)(__VA_ARGS__)\n\n}}\n\n#include \"Registration-inl.h\"\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni/TypeTraits.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <type_traits>\n\n#include \"References-forward.h\"\n\nnamespace facebook {\nnamespace jni {\n\n/// Generic std::enable_if helper\ntemplate<bool B, typename T>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\n/// Generic std::is_convertible helper\ntemplate<typename From, typename To>\nconstexpr bool IsConvertible() {\n  return std::is_convertible<From, To>::value;\n}\n\ntemplate<template<typename...> class TT, typename T>\nstruct is_instantiation_of : std::false_type {};\n\ntemplate<template<typename...> class TT, typename... Ts>\nstruct is_instantiation_of<TT, TT<Ts...>> : std::true_type {};\n\ntemplate<template<typename...> class TT, typename... Ts>\nconstexpr bool IsInstantiationOf() {\n  return is_instantiation_of<TT, Ts...>::value;\n}\n\n/// Metafunction to determine whether a type is a JNI reference or not\ntemplate<typename T>\nstruct is_plain_jni_reference :\n  std::integral_constant<bool,\n      std::is_pointer<T>::value &&\n      std::is_base_of<\n        typename std::remove_pointer<jobject>::type,\n        typename std::remove_pointer<T>::type>::value> {};\n\n/// Helper to simplify use of is_plain_jni_reference\ntemplate<typename T>\nconstexpr bool IsPlainJniReference() {\n  return is_plain_jni_reference<T>::value;\n}\n\n/// Metafunction to determine whether a type is a primitive JNI type or not\ntemplate<typename T>\nstruct is_jni_primitive :\n  std::integral_constant<bool,\n    std::is_same<jboolean, T>::value ||\n    std::is_same<jbyte, T>::value ||\n    std::is_same<jchar, T>::value ||\n    std::is_same<jshort, T>::value ||\n    std::is_same<jint, T>::value ||\n    std::is_same<jlong, T>::value ||\n    std::is_same<jfloat, T>::value ||\n    std::is_same<jdouble, T>::value> {};\n\n/// Helper to simplify use of is_jni_primitive\ntemplate<typename T>\nconstexpr bool IsJniPrimitive() {\n  return is_jni_primitive<T>::value;\n}\n\n/// Metafunction to determine whether a type is a JNI array of primitives or not\ntemplate <typename T>\nstruct is_jni_primitive_array :\n  std::integral_constant<bool,\n    std::is_same<jbooleanArray, T>::value ||\n    std::is_same<jbyteArray, T>::value ||\n    std::is_same<jcharArray, T>::value ||\n    std::is_same<jshortArray, T>::value ||\n    std::is_same<jintArray, T>::value ||\n    std::is_same<jlongArray, T>::value ||\n    std::is_same<jfloatArray, T>::value ||\n    std::is_same<jdoubleArray, T>::value> {};\n\n/// Helper to simplify use of is_jni_primitive_array\ntemplate <typename T>\nconstexpr bool IsJniPrimitiveArray() {\n  return is_jni_primitive_array<T>::value;\n}\n\n/// Metafunction to determine if a type is a scalar (primitive or reference) JNI type\ntemplate<typename T>\nstruct is_jni_scalar :\n  std::integral_constant<bool,\n    is_plain_jni_reference<T>::value ||\n    is_jni_primitive<T>::value> {};\n\n/// Helper to simplify use of is_jni_scalar\ntemplate<typename T>\nconstexpr bool IsJniScalar() {\n  return is_jni_scalar<T>::value;\n}\n\n// Metafunction to determine if a type is a JNI type\ntemplate<typename T>\nstruct is_jni_type :\n  std::integral_constant<bool,\n    is_jni_scalar<T>::value ||\n    std::is_void<T>::value> {};\n\n/// Helper to simplify use of is_jni_type\ntemplate<typename T>\nconstexpr bool IsJniType() {\n  return is_jni_type<T>::value;\n}\n\ntemplate<typename T>\nstruct is_non_weak_reference :\n  std::integral_constant<bool,\n    IsPlainJniReference<T>() ||\n    IsInstantiationOf<basic_strong_ref, T>() ||\n    IsInstantiationOf<alias_ref, T>()> {};\n\ntemplate<typename T>\nconstexpr bool IsNonWeakReference() {\n  return is_non_weak_reference<T>::value;\n}\n\ntemplate<typename T>\nstruct is_any_reference :\n  std::integral_constant<bool,\n    IsPlainJniReference<T>() ||\n    IsInstantiationOf<weak_ref, T>() ||\n    IsInstantiationOf<basic_strong_ref, T>() ||\n    IsInstantiationOf<alias_ref, T>()> {};\n\ntemplate<typename T>\nconstexpr bool IsAnyReference() {\n  return is_any_reference<T>::value;\n}\n\ntemplate<typename T>\nstruct reference_traits {\n  using plain_jni_reference_t = JniType<T>;\n  static_assert(IsPlainJniReference<plain_jni_reference_t>(), \"Need a plain JNI reference\");\n};\n\ntemplate<template <typename...> class R, typename T, typename... A>\nstruct reference_traits<R<T, A...>> {\n  using plain_jni_reference_t = JniType<T>;\n  static_assert(IsPlainJniReference<plain_jni_reference_t>(), \"Need a plain JNI reference\");\n};\n\ntemplate<typename T>\nusing plain_jni_reference_t = typename reference_traits<T>::plain_jni_reference_t;\n\n} // namespace jni\n} // namespace facebook\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/fbjni.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <jni.h>\n\n#include <fb/Environment.h>\n#include <fb/ALog.h>\n#include <fb/fbjni/Common.h>\n#include <fb/fbjni/Exceptions.h>\n#include <fb/fbjni/ReferenceAllocators.h>\n#include <fb/fbjni/References.h>\n#include <fb/fbjni/Meta.h>\n#include <fb/fbjni/CoreClasses.h>\n#include <fb/fbjni/Iterator.h>\n#include <fb/fbjni/Hybrid.h>\n#include <fb/fbjni/Registration.h>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/log.h",
    "content": "/*\n * Copyright (C) 2005 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * FB Wrapper for logging functions.\n *\n * The android logging API uses the macro \"LOG()\" for its logic, which means\n * that it conflicts with random other places that use LOG for their own\n * purposes and doesn't work right half the places you include it\n *\n * FBLOG uses exactly the same semantics (FBLOGD for debug etc) but because of\n * the FB prefix it's strictly better. FBLOGV also gets stripped out based on\n * whether NDEBUG is set, but can be overridden by FBLOG_NDEBUG\n *\n * Most of the rest is a copy of <cutils/log.h> with minor changes.\n */\n\n//\n// C/C++ logging functions.  See the logging documentation for API details.\n//\n// We'd like these to be available from C code (in case we import some from\n// somewhere), so this has a C interface.\n//\n// The output will be correct when the log file is shared between multiple\n// threads and/or multiple processes so long as the operating system\n// supports O_APPEND.  These calls have mutex-protected data structures\n// and so are NOT reentrant.  Do not use LOG in a signal handler.\n//\n#pragma once\n\n#include <fb/visibility.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef ANDROID\n#include <android/log.h>\n#else\n// These declarations are needed for our internal use even on non-Android\n// builds.\n// (they are borrowed from <android/log.h>)\n\n/*\n * Android log priority values, in ascending priority order.\n */\ntypedef enum android_LogPriority {\n  ANDROID_LOG_UNKNOWN = 0,\n  ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */\n  ANDROID_LOG_VERBOSE,\n  ANDROID_LOG_DEBUG,\n  ANDROID_LOG_INFO,\n  ANDROID_LOG_WARN,\n  ANDROID_LOG_ERROR,\n  ANDROID_LOG_FATAL,\n  ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */\n} android_LogPriority;\n\n/*\n * Send a simple string to the log.\n */\nint __android_log_write(int prio, const char *tag, const char *text);\n\n/*\n * Send a formatted string to the log, used like printf(fmt,...)\n */\nint __android_log_print(int prio, const char *tag, const char *fmt, ...)\n#if defined(__GNUC__)\n    __attribute__((format(printf, 3, 4)))\n#endif\n    ;\n\n#endif\n\n// ---------------------------------------------------------------------\n\n/*\n * Normally we strip FBLOGV (VERBOSE messages) from release builds.\n * You can modify this (for example with \"#define FBLOG_NDEBUG 0\"\n * at the top of your source file) to change that behavior.\n */\n#ifndef FBLOG_NDEBUG\n#ifdef NDEBUG\n#define FBLOG_NDEBUG 1\n#else\n#define FBLOG_NDEBUG 0\n#endif\n#endif\n\n/*\n * This is the local tag used for the following simplified\n * logging macros.  You can change this preprocessor definition\n * before using the other macros to change the tag.\n */\n#ifndef LOG_TAG\n#define LOG_TAG NULL\n#endif\n\n// ---------------------------------------------------------------------\n\n/*\n * Simplified macro to send a verbose log message using the current LOG_TAG.\n */\n#ifndef FBLOGV\n#if FBLOG_NDEBUG\n#define FBLOGV(...) ((void)0)\n#else\n#define FBLOGV(...) ((void)FBLOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))\n#endif\n#endif\n\n#define CONDITION(cond) (__builtin_expect((cond) != 0, 0))\n\n#ifndef FBLOGV_IF\n#if FBLOG_NDEBUG\n#define FBLOGV_IF(cond, ...) ((void)0)\n#else\n#define FBLOGV_IF(cond, ...)                                            \\\n  ((CONDITION(cond)) ? ((void)FBLOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \\\n                     : (void)0)\n#endif\n#endif\n\n/*\n * Simplified macro to send a debug log message using the current LOG_TAG.\n */\n#ifndef FBLOGD\n#define FBLOGD(...) ((void)FBLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))\n#endif\n\n#ifndef FBLOGD_IF\n#define FBLOGD_IF(cond, ...) \\\n  ((CONDITION(cond)) ? ((void)FBLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) : (void)0)\n#endif\n\n/*\n * Simplified macro to send an info log message using the current LOG_TAG.\n */\n#ifndef FBLOGI\n#define FBLOGI(...) ((void)FBLOG(LOG_INFO, LOG_TAG, __VA_ARGS__))\n#endif\n\n#ifndef FBLOGI_IF\n#define FBLOGI_IF(cond, ...) \\\n  ((CONDITION(cond)) ? ((void)FBLOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) : (void)0)\n#endif\n\n/*\n * Simplified macro to send a warning log message using the current LOG_TAG.\n */\n#ifndef FBLOGW\n#define FBLOGW(...) ((void)FBLOG(LOG_WARN, LOG_TAG, __VA_ARGS__))\n#endif\n\n#ifndef FBLOGW_IF\n#define FBLOGW_IF(cond, ...) \\\n  ((CONDITION(cond)) ? ((void)FBLOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) : (void)0)\n#endif\n\n/*\n * Simplified macro to send an error log message using the current LOG_TAG.\n */\n#ifndef FBLOGE\n#define FBLOGE(...) ((void)FBLOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))\n#endif\n\n#ifndef FBLOGE_IF\n#define FBLOGE_IF(cond, ...) \\\n  ((CONDITION(cond)) ? ((void)FBLOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) : (void)0)\n#endif\n\n// ---------------------------------------------------------------------\n\n/*\n * Conditional based on whether the current LOG_TAG is enabled at\n * verbose priority.\n */\n#ifndef IF_FBLOGV\n#if FBLOG_NDEBUG\n#define IF_FBLOGV() if (false)\n#else\n#define IF_FBLOGV() IF_FBLOG(LOG_VERBOSE, LOG_TAG)\n#endif\n#endif\n\n/*\n * Conditional based on whether the current LOG_TAG is enabled at\n * debug priority.\n */\n#ifndef IF_FBLOGD\n#define IF_FBLOGD() IF_FBLOG(LOG_DEBUG, LOG_TAG)\n#endif\n\n/*\n * Conditional based on whether the current LOG_TAG is enabled at\n * info priority.\n */\n#ifndef IF_FBLOGI\n#define IF_FBLOGI() IF_FBLOG(LOG_INFO, LOG_TAG)\n#endif\n\n/*\n * Conditional based on whether the current LOG_TAG is enabled at\n * warn priority.\n */\n#ifndef IF_FBLOGW\n#define IF_FBLOGW() IF_FBLOG(LOG_WARN, LOG_TAG)\n#endif\n\n/*\n * Conditional based on whether the current LOG_TAG is enabled at\n * error priority.\n */\n#ifndef IF_FBLOGE\n#define IF_FBLOGE() IF_FBLOG(LOG_ERROR, LOG_TAG)\n#endif\n\n// ---------------------------------------------------------------------\n\n/*\n * Log a fatal error.  If the given condition fails, this stops program\n * execution like a normal assertion, but also generating the given message.\n * It is NOT stripped from release builds.  Note that the condition test\n * is -inverted- from the normal assert() semantics.\n */\n#define FBLOG_ALWAYS_FATAL_IF(cond, ...)                                   \\\n  ((CONDITION(cond)) ? ((void)fb_printAssert(#cond, LOG_TAG, __VA_ARGS__)) \\\n                     : (void)0)\n\n#define FBLOG_ALWAYS_FATAL(...) \\\n  (((void)fb_printAssert(NULL, LOG_TAG, __VA_ARGS__)))\n\n/*\n * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that\n * are stripped out of release builds.\n */\n#if FBLOG_NDEBUG\n\n#define FBLOG_FATAL_IF(cond, ...) ((void)0)\n#define FBLOG_FATAL(...) ((void)0)\n\n#else\n\n#define FBLOG_FATAL_IF(cond, ...) FBLOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__)\n#define FBLOG_FATAL(...) FBLOG_ALWAYS_FATAL(__VA_ARGS__)\n\n#endif\n\n/*\n * Assertion that generates a log message when the assertion fails.\n * Stripped out of release builds.  Uses the current LOG_TAG.\n */\n#define FBLOG_ASSERT(cond, ...) FBLOG_FATAL_IF(!(cond), __VA_ARGS__)\n//#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), \"Assertion failed: \" #cond)\n\n// ---------------------------------------------------------------------\n\n/*\n * Basic log message macro.\n *\n * Example:\n *  FBLOG(LOG_WARN, NULL, \"Failed with error %d\", errno);\n *\n * The second argument may be NULL or \"\" to indicate the \"global\" tag.\n */\n#ifndef FBLOG\n#define FBLOG(priority, tag, ...) \\\n  FBLOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)\n#endif\n\n#ifndef FBLOG_BY_DELIMS\n#define FBLOG_BY_DELIMS(priority, tag, delims, msg, ...) \\\n  logPrintByDelims(ANDROID_##priority, tag, delims, msg, ##__VA_ARGS__)\n#endif\n\n/*\n * Log macro that allows you to specify a number for the priority.\n */\n#ifndef FBLOG_PRI\n#define FBLOG_PRI(priority, tag, ...) fb_printLog(priority, tag, __VA_ARGS__)\n#endif\n\n/*\n * Log macro that allows you to pass in a varargs (\"args\" is a va_list).\n */\n#ifndef FBLOG_PRI_VA\n#define FBLOG_PRI_VA(priority, tag, fmt, args) \\\n  fb_vprintLog(priority, NULL, tag, fmt, args)\n#endif\n\n/*\n * Conditional given a desired logging priority and tag.\n */\n#ifndef IF_FBLOG\n#define IF_FBLOG(priority, tag) if (fb_testLog(ANDROID_##priority, tag))\n#endif\n\ntypedef void (*LogHandler)(int priority, const char* tag, const char* message);\nFBEXPORT void setLogHandler(LogHandler logHandler);\n\n/*\n * ===========================================================================\n *\n * The stuff in the rest of this file should not be used directly.\n */\nFBEXPORT int fb_printLog(int prio, const char* tag, const char* fmt, ...)\n#if defined(__GNUC__)\n    __attribute__((format(printf, 3, 4)))\n#endif\n    ;\n\n#define fb_vprintLog(prio, cond, tag, fmt...) \\\n  __android_log_vprint(prio, tag, fmt)\n\n#define fb_printAssert(cond, tag, fmt...) __android_log_assert(cond, tag, fmt)\n\n#define fb_writeLog(prio, tag, text) __android_log_write(prio, tag, text)\n\n#define fb_bWriteLog(tag, payload, len) __android_log_bwrite(tag, payload, len)\n#define fb_btWriteLog(tag, type, payload, len) \\\n  __android_log_btwrite(tag, type, payload, len)\n\n#define fb_testLog(prio, tag) (1)\n\n/*\n * FB extensions\n */\nvoid logPrintByDelims(int priority, const char* tag, const char* delims,\n                      const char* msg, ...);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/lyra.h",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#pragma once\n\n#include <iomanip>\n#include <iostream>\n#include <string>\n#include <vector>\n\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace lyra {\n\nconstexpr size_t kDefaultLimit = 64;\n\nusing InstructionPointer = const void*;\n\nclass FBEXPORT StackTraceElement {\n public:\n  StackTraceElement(InstructionPointer absoluteProgramCounter,\n                    InstructionPointer libraryBase,\n                    InstructionPointer functionAddress, std::string libraryName,\n                    std::string functionName)\n      : absoluteProgramCounter_{absoluteProgramCounter},\n        libraryBase_{libraryBase},\n        functionAddress_{functionAddress},\n        libraryName_{std::move(libraryName)},\n        functionName_{std::move(functionName)} {}\n\n  InstructionPointer libraryBase() const noexcept { return libraryBase_; }\n\n  InstructionPointer functionAddress() const noexcept {\n    return functionAddress_;\n  }\n\n  InstructionPointer absoluteProgramCounter() const noexcept {\n    return absoluteProgramCounter_;\n  }\n\n  const std::string& libraryName() const noexcept { return libraryName_; }\n\n  const std::string& functionName() const noexcept { return functionName_; }\n\n  /**\n   * The offset of the program counter to the base of the library (i.e. the\n   * address that addr2line takes as input>\n   */\n  std::ptrdiff_t libraryOffset() const noexcept {\n    auto absoluteLibrary = static_cast<const char*>(libraryBase_);\n    auto absoluteabsoluteProgramCounter =\n        static_cast<const char*>(absoluteProgramCounter_);\n    return absoluteabsoluteProgramCounter - absoluteLibrary;\n  }\n\n  /**\n   * The offset within the current function\n   */\n  int functionOffset() const noexcept {\n    auto absoluteSymbol = static_cast<const char*>(functionAddress_);\n    auto absoluteabsoluteProgramCounter =\n        static_cast<const char*>(absoluteProgramCounter_);\n    return absoluteabsoluteProgramCounter - absoluteSymbol;\n  }\n\n private:\n  const InstructionPointer absoluteProgramCounter_;\n  const InstructionPointer libraryBase_;\n  const InstructionPointer functionAddress_;\n  const std::string libraryName_;\n  const std::string functionName_;\n};\n\n/**\n * Populate the vector with the current stack trace\n *\n * Note that this trace needs to be symbolicated to get the library offset even\n * if it is to be symbolicated off-line.\n *\n * Beware of a bug on some platforms, which makes the trace loop until the\n * buffer is full when it reaches a noexpr function. It seems to be fixed in\n * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846\n *\n * @param stackTrace The vector that will receive the stack trace. Before\n * filling the vector it will be cleared. The vector will never grow so the\n * number of frames captured is limited by the capacity of it.\n *\n * @param skip The number of frames to skip before capturing the trace\n */\nFBEXPORT void getStackTrace(std::vector<InstructionPointer>& stackTrace,\n                            size_t skip = 0);\n\n/**\n * Creates a vector and populates it with the current stack trace\n *\n * Note that this trace needs to be symbolicated to get the library offset even\n * if it is to be symbolicated off-line.\n *\n * Beware of a bug on some platforms, which makes the trace loop until the\n * buffer is full when it reaches a noexpr function. It seems to be fixed in\n * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846\n *\n * @param skip The number of frames to skip before capturing the trace\n *\n * @limit The maximum number of frames captured\n */\nFBEXPORT inline std::vector<InstructionPointer> getStackTrace(\n    size_t skip = 0,\n    size_t limit = kDefaultLimit) {\n  auto stackTrace = std::vector<InstructionPointer>{};\n  stackTrace.reserve(limit);\n  getStackTrace(stackTrace, skip + 1);\n  return stackTrace;\n}\n\n/**\n * Symbolicates a stack trace into a given vector\n *\n * @param symbols The vector to receive the output. The vector is cleared and\n * enough room to keep the frames are reserved.\n *\n * @param stackTrace The input stack trace\n */\nFBEXPORT void getStackTraceSymbols(std::vector<StackTraceElement>& symbols,\n                                   const std::vector<InstructionPointer>& trace);\n\n/**\n * Symbolicates a stack trace into a new vector\n *\n * @param stackTrace The input stack trace\n */\nFBEXPORT inline std::vector<StackTraceElement> getStackTraceSymbols(\n    const std::vector<InstructionPointer>& trace) {\n  auto symbols = std::vector<StackTraceElement>{};\n  getStackTraceSymbols(symbols, trace);\n  return symbols;\n}\n\n\n/**\n * Captures and symbolicates a stack trace\n *\n * Beware of a bug on some platforms, which makes the trace loop until the\n * buffer is full when it reaches a noexpr function. It seems to be fixed in\n * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846\n *\n * @param skip The number of frames before capturing the trace\n *\n * @param limit The maximum number of frames captured\n */\nFBEXPORT inline std::vector<StackTraceElement> getStackTraceSymbols(\n    size_t skip = 0,\n    size_t limit = kDefaultLimit) {\n  return getStackTraceSymbols(getStackTrace(skip + 1, limit));\n}\n\n/**\n * Formatting a stack trace element\n */\nFBEXPORT std::ostream& operator<<(std::ostream& out, const StackTraceElement& elm);\n\n/**\n * Formatting a stack trace\n */\nFBEXPORT std::ostream& operator<<(std::ostream& out,\n                                  const std::vector<StackTraceElement>& trace);\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/noncopyable.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\nnamespace facebook {\n\nstruct noncopyable {\n  noncopyable(const noncopyable&) = delete;\n  noncopyable& operator=(const noncopyable&) = delete;\nprotected:\n  noncopyable() = default;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/nonmovable.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\nnamespace facebook {\n\nstruct nonmovable {\n  nonmovable(nonmovable&&) = delete;\n  nonmovable& operator=(nonmovable&&) = delete;\nprotected:\n  nonmovable() = default;\n};\n\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/fb/visibility.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#define FBEXPORT __attribute__((visibility(\"default\")))\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/Countable.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <jni.h>\n\n#include <fb/Countable.h>\n#include <fb/RefPtr.h>\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace jni {\n\nFBEXPORT const RefPtr<Countable>& countableFromJava(JNIEnv* env, jobject obj);\n\ntemplate <typename T> RefPtr<T> extractRefPtr(JNIEnv* env, jobject obj) {\n  return static_cast<RefPtr<T>>(countableFromJava(env, obj));\n}\n\ntemplate <typename T> RefPtr<T> extractPossiblyNullRefPtr(JNIEnv* env, jobject obj) {\n  return obj ? extractRefPtr<T>(env, obj) : nullptr;\n}\n\nFBEXPORT void setCountableForJava(JNIEnv* env, jobject obj, RefPtr<Countable>&& countable);\n\nvoid CountableOnLoad(JNIEnv* env);\n\n} }\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/GlobalReference.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <memory>\n#include <type_traits>\n\n#include <jni.h>\n\n#include <fb/Environment.h>\n\nnamespace facebook { namespace jni {\n\ntemplate<typename T>\nclass GlobalReference {\n  static_assert(std::is_convertible<T, jobject>::value,\n                \"GlobalReference<T> instantiated with type that is not \"\n                \"convertible to jobject\");\n\n public:\n  explicit GlobalReference(T globalReference) :\n    reference_(globalReference? Environment::current()->NewGlobalRef(globalReference) : nullptr) {\n  }\n\n  ~GlobalReference() {\n    reset();\n  }\n\n  GlobalReference() :\n    reference_(nullptr) {\n  }\n\n  // enable move constructor and assignment\n  GlobalReference(GlobalReference&& rhs) :\n    reference_(std::move(rhs.reference_)) {\n    rhs.reference_ = nullptr;\n  }\n\n  GlobalReference& operator=(GlobalReference&& rhs) {\n    if (this != &rhs) {\n      reset();\n      reference_ = std::move(rhs.reference_);\n      rhs.reference_ = nullptr;\n    }\n    return *this;\n  }\n\n  GlobalReference(const GlobalReference<T>& rhs) :\n    reference_{} {\n    reset(rhs.get());\n  }\n\n  GlobalReference& operator=(const GlobalReference<T>& rhs) {\n    if (this == &rhs) {\n      return *this;\n    }\n    reset(rhs.get());\n    return *this;\n  }\n\n  explicit operator bool() const {\n    return (reference_ != nullptr);\n  }\n\n  T get() const {\n    return reinterpret_cast<T>(reference_);\n  }\n\n  void reset(T globalReference = nullptr) {\n    if (reference_) {\n      Environment::current()->DeleteGlobalRef(reference_);\n    }\n    if (globalReference) {\n      reference_ = Environment::current()->NewGlobalRef(globalReference);\n    } else {\n      reference_ = nullptr;\n    }\n  }\n\n private:\n  jobject reference_;\n};\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/JniTerminateHandler.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace jni {\n\nvoid FBEXPORT installTerminateHandler();\n}};\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/LocalReference.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <memory>\n#include <type_traits>\n\n#include <jni.h>\n\n#include <fb/Environment.h>\n\nnamespace facebook {\nnamespace jni {\n\ntemplate<class T>\nstruct LocalReferenceDeleter {\n  static_assert(std::is_convertible<T, jobject>::value,\n    \"LocalReferenceDeleter<T> instantiated with type that is not convertible to jobject\");\n  void operator()(T localReference) {\n    if (localReference != nullptr) {\n      Environment::current()->DeleteLocalRef(localReference);\n    }\n  } \n };\n\ntemplate<class T>\nusing LocalReference =\n  std::unique_ptr<typename std::remove_pointer<T>::type, LocalReferenceDeleter<T>>;\n\n} }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/LocalString.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <string>\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\nvoid utf8ToModifiedUTF8(const uint8_t* bytes, size_t len, uint8_t* modified, size_t modifiedLength);\nsize_t modifiedLength(const std::string& str);\nsize_t modifiedLength(const uint8_t* str, size_t* length);\nstd::string modifiedUTF8ToUTF8(const uint8_t* modified, size_t len) noexcept;\nstd::string utf16toUTF8(const uint16_t* utf16Bytes, size_t len) noexcept;\n\n}\n\n// JNI represents strings encoded with modified version of UTF-8.  The difference between UTF-8 and\n// Modified UTF-8 is that the latter support only 1-byte, 2-byte, and 3-byte formats. Supplementary\n// character (4 bytes in unicode) needs to be represented in the form of surrogate pairs. To create\n// a Modified UTF-8 surrogate pair that Dalvik would understand we take 4-byte unicode character,\n// encode it with UTF-16 which gives us two 2 byte chars (surrogate pair) and then we encode each\n// pair as UTF-8. This result in 2 x 3 byte characters.  To convert modified UTF-8 to standard\n// UTF-8, this mus tbe reversed.\n//\n// The second difference is that Modified UTF-8 is encoding NUL byte in 2-byte format.\n//\n// In order to avoid complex error handling, only a minimum of validity checking is done to avoid\n// crashing.  If the input is invalid, the output may be invalid as well.\n//\n// Relevant links:\n//  - http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html\n//  - https://docs.oracle.com/javase/6/docs/api/java/io/DataInput.html#modified-utf-8\n\nclass FBEXPORT LocalString {\npublic:\n  // Assumes UTF8 encoding and make a required convertion to modified UTF-8 when the string\n  // contains unicode supplementary characters.\n  explicit LocalString(const std::string& str);\n  explicit LocalString(const char* str);\n  jstring string() const {\n    return m_string;\n  }\n  ~LocalString();\nprivate:\n  jstring m_string;\n};\n\n// JString to UTF16 extractor using RAII idiom\nclass JStringUtf16Extractor {\npublic:\n  JStringUtf16Extractor(JNIEnv* env, jstring javaString)\n  : env_(env)\n  , javaString_(javaString)\n  , length_(0)\n  , utf16String_(nullptr) {\n    if (env_ && javaString_) {\n      length_ = env_->GetStringLength(javaString_);\n      utf16String_ = env_->GetStringCritical(javaString_, nullptr);\n    }\n  }\n\n  ~JStringUtf16Extractor() {\n    if (utf16String_) {\n      env_->ReleaseStringCritical(javaString_, utf16String_);\n    }\n  }\n\n  const jsize length() const {\n    return length_;\n  }\n\n  const jchar* chars() const {\n    return utf16String_;\n  }\n\nprivate:\n  JNIEnv* env_;\n  jstring javaString_;\n  jsize length_;\n  const jchar* utf16String_;\n};\n\n// The string from JNI is converted to standard UTF-8 if the string contains supplementary\n// characters.\nFBEXPORT std::string fromJString(JNIEnv* env, jstring str);\n\n} }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/Registration.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <jni.h>\n#include <initializer_list>\n#include <fb/assert.h>\n\nnamespace facebook {\nnamespace jni {\n\nstatic inline void registerNatives(JNIEnv* env, jclass cls, std::initializer_list<JNINativeMethod> methods) {\n  auto result = env->RegisterNatives(cls, methods.begin(), methods.size());\n  FBASSERT(result == 0);\n}\n\nstatic inline void registerNatives(JNIEnv* env, const char* cls, std::initializer_list<JNINativeMethod> list) {\n  registerNatives(env, env->FindClass(cls), list);\n}\n\n} }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/WeakReference.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n#include <string>\n#include <jni.h>\n#include <fb/noncopyable.h>\n#include <fb/Countable.h>\n#include <fb/visibility.h>\n\n\nnamespace facebook {\nnamespace jni {\n\nclass FBEXPORT WeakReference : public Countable {\npublic:\n  typedef RefPtr<WeakReference> Ptr;\n  WeakReference(jobject strongRef);\n  ~WeakReference();\n  jweak weakRef() {\n    return m_weakReference;\n  }\n\nprivate:\n  jweak m_weakReference;\n};\n\n// This class is intended to take a weak reference and turn it into a strong\n// local reference. Consequently, it should only be allocated on the stack.\nclass FBEXPORT ResolvedWeakReference : public noncopyable {\npublic:\n  ResolvedWeakReference(jobject weakRef);\n  ResolvedWeakReference(const RefPtr<WeakReference>& weakRef);\n  ~ResolvedWeakReference();\n\n  operator jobject () {\n    return m_strongReference;\n  }\n\n  explicit operator bool () {\n    return m_strongReference != nullptr;\n  }\n\nprivate:\n  jobject m_strongReference;\n};\n\n} }\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/include/jni/jni_helpers.h",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#pragma once\n\n#include <jni.h>\n\n#include <fb/visibility.h>\n\nnamespace facebook {\n\n/**\n * Instructs the JNI environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param szClassName class name to throw\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwException(JNIEnv* pEnv, const char* szClassName, const char* szFmt, va_list va_args);\n\n/**\n * Instructs the JNI environment to throw a NoClassDefFoundError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwNoClassDefError(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw a RuntimeException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwRuntimeException(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw a IllegalArgumentException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwIllegalArgumentException(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw a IllegalStateException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwIllegalStateException(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw an IOException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwIOException(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw an AssertionError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwAssertionError(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Instructs the JNI environment to throw an OutOfMemoryError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\nFBEXPORT jint throwOutOfMemoryError(JNIEnv* pEnv, const char* szFmt, ...);\n\n/**\n * Finds the specified class. If it's not found, instructs the JNI environment to throw an\n * exception.\n *\n * @param pEnv JNI environment\n * @param szClassName the classname to find in JNI format (e.g. \"java/lang/String\")\n * @return the class or NULL if not found (in which case a pending exception will be queued). This\n *     returns a global reference (JNIEnv::NewGlobalRef).\n */\nFBEXPORT jclass findClassOrThrow(JNIEnv *pEnv, const char* szClassName);\n\n/**\n * Finds the specified field of the specified class. If it's not found, instructs the JNI\n * environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param clazz the class to lookup the field in\n * @param szFieldName the name of the field to find\n * @param szSig the signature of the field\n * @return the field or NULL if not found (in which case a pending exception will be queued)\n */\nFBEXPORT jfieldID getFieldIdOrThrow(JNIEnv* pEnv, jclass clazz, const char* szFieldName, const char* szSig);\n\n/**\n * Finds the specified method of the specified class. If it's not found, instructs the JNI\n * environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param clazz the class to lookup the method in\n * @param szMethodName the name of the method to find\n * @param szSig the signature of the method\n * @return the method or NULL if not found (in which case a pending exception will be queued)\n */\nFBEXPORT jmethodID getMethodIdOrThrow(\n    JNIEnv* pEnv,\n    jclass clazz,\n    const char* szMethodName,\n    const char* szSig);\n\n} // namespace facebook\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/ByteBuffer.cpp",
    "content": "/*\n * Copyright (c) 2016-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/fbjni/ByteBuffer.h>\n\n#include <stdexcept>\n\n#include <fb/fbjni/References.h>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace {\nlocal_ref<JByteBuffer> createEmpty() {\n  static auto cls = JByteBuffer::javaClassStatic();\n  static auto meth = cls->getStaticMethod<JByteBuffer::javaobject(int)>(\"allocateDirect\");\n  return meth(cls, 0);\n}\n}\n\nlocal_ref<JByteBuffer> JByteBuffer::wrapBytes(uint8_t* data, size_t size) {\n  // env->NewDirectByteBuffer requires that size is positive. Android's\n  // dalvik returns an invalid result and Android's art aborts if size == 0.\n  // Workaround this by using a slow path through Java in that case.\n  if (!size) {\n    return createEmpty();\n  }\n  auto res = adopt_local(static_cast<javaobject>(Environment::current()->NewDirectByteBuffer(data, size)));\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  if (!res) {\n    throw std::runtime_error(\"Direct byte buffers are unsupported.\");\n  }\n  return res;\n}\n\nuint8_t* JByteBuffer::getDirectBytes() const {\n  if (!self()) {\n    throwNewJavaException(\"java/lang/NullPointerException\", \"java.lang.NullPointerException\");\n  }\n  void* bytes = Environment::current()->GetDirectBufferAddress(self());\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  if (!bytes) {\n    throw std::runtime_error(\n        isDirect() ?\n          \"Attempt to get direct bytes of non-direct byte buffer.\" :\n          \"Error getting direct bytes of byte buffer.\");\n  }\n  return static_cast<uint8_t*>(bytes);\n}\n\nsize_t JByteBuffer::getDirectSize() const {\n  if (!self()) {\n    throwNewJavaException(\"java/lang/NullPointerException\", \"java.lang.NullPointerException\");\n  }\n  int size = Environment::current()->GetDirectBufferCapacity(self());\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  if (size < 0) {\n    throw std::runtime_error(\n        isDirect() ?\n          \"Attempt to get direct size of non-direct byte buffer.\" :\n          \"Error getting direct size of byte buffer.\");\n  }\n  return static_cast<size_t>(size);\n}\n\nbool JByteBuffer::isDirect() const {\n  static auto meth = javaClassStatic()->getMethod<jboolean()>(\"isDirect\");\n  return meth(self());\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/Countable.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <cstdint>\n#include <jni/Countable.h>\n#include <fb/Environment.h>\n#include <jni/Registration.h>\n\nnamespace facebook {\nnamespace jni {\n\nstatic jfieldID gCountableNativePtr;\n\nstatic RefPtr<Countable>* rawCountableFromJava(JNIEnv* env, jobject obj) {\n  FBASSERT(obj);\n  return reinterpret_cast<RefPtr<Countable>*>(env->GetLongField(obj, gCountableNativePtr));\n}\n\nconst RefPtr<Countable>& countableFromJava(JNIEnv* env, jobject obj) {\n  FBASSERT(obj);\n  return *rawCountableFromJava(env, obj);\n}\n\nvoid setCountableForJava(JNIEnv* env, jobject obj, RefPtr<Countable>&& countable) {\n  int oldValue = env->GetLongField(obj, gCountableNativePtr);\n  FBASSERTMSGF(oldValue == 0, \"Cannot reinitialize object; expected nullptr, got %x\", oldValue);\n\n  FBASSERT(countable);\n  uintptr_t fieldValue = (uintptr_t) new RefPtr<Countable>(std::move(countable));\n  env->SetLongField(obj, gCountableNativePtr, fieldValue);\n}\n\n/**\n * NB: THREAD SAFETY (this comment also exists at Countable.java)\n *\n * This method deletes the corresponding native object on whatever thread the method is called\n * on. In the common case when this is called by Countable#finalize(), this will be called on the\n * system finalizer thread. If you manually call dispose on the Java object, the native object \n * will be deleted synchronously on that thread.\n */\nvoid dispose(JNIEnv* env, jobject obj) {\n  // Grab the pointer\n  RefPtr<Countable>* countable = rawCountableFromJava(env, obj);\n  if (!countable) {\n    // That was easy.\n    return;\n  }\n\n  // Clear out the old value to avoid double-frees\n  env->SetLongField(obj, gCountableNativePtr, 0);\n\n  delete countable;\n}\n\nvoid CountableOnLoad(JNIEnv* env) {\n  jclass countable = env->FindClass(\"com/facebook/jni/Countable\");\n  gCountableNativePtr = env->GetFieldID(countable, \"mInstance\", \"J\");\n  registerNatives(env, countable, {\n    { \"dispose\", \"()V\", (void*) dispose },\n  });\n}\n\n} }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/Environment.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/log.h>\n#include <fb/ThreadLocal.h>\n#include <fb/Environment.h>\n#include <fb/fbjni/CoreClasses.h>\n#include <fb/fbjni/NativeRunnable.h>\n\n#include <functional>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace {\n\nThreadLocal<ThreadScope>& scopeStorage() {\n  // We don't want the ThreadLocal to delete the ThreadScopes.\n  static ThreadLocal<ThreadScope> scope([] (void*) {});\n  return scope;\n}\n\nThreadScope* currentScope() {\n  return scopeStorage().get();\n}\n\nJavaVM* g_vm = nullptr;\n\nstruct EnvironmentInitializer {\n  EnvironmentInitializer(JavaVM* vm) {\n      FBASSERT(!g_vm);\n      FBASSERT(vm);\n      g_vm = vm;\n  }\n};\n\nint getEnv(JNIEnv** env) {\n  FBASSERT(g_vm);\n  // g_vm->GetEnv() might not clear the env* in failure cases.\n  *env = nullptr;\n  return g_vm->GetEnv((void**)env, JNI_VERSION_1_6);\n}\n\nJNIEnv* attachCurrentThread() {\n  JavaVMAttachArgs args{JNI_VERSION_1_6, nullptr, nullptr};\n  JNIEnv* env = nullptr;\n  auto result = g_vm->AttachCurrentThread(&env, &args);\n  FBASSERT(result == JNI_OK);\n  return env;\n}\n}\n\n/* static */\nvoid Environment::initialize(JavaVM* vm) {\n  static EnvironmentInitializer init(vm);\n}\n\n/* static */\nJNIEnv* Environment::current() {\n  auto scope = currentScope();\n  if (scope && scope->env_) {\n    return scope->env_;\n  }\n\n  JNIEnv* env;\n  if (getEnv(&env) != JNI_OK) {\n    // If there's a ThreadScope in the stack, we should be attached and able to\n    // retrieve a JNIEnv*.\n    FBASSERT(!scope);\n\n    // TODO(cjhopman): this should probably be a hard failure, too.\n    FBLOGE(\"Unable to retrieve jni environment. Is the thread attached?\");\n  }\n  return env;\n}\n\n/* static */\nvoid Environment::detachCurrentThread() {\n  FBASSERT(g_vm);\n  // The thread shouldn't be detached while a ThreadScope is in the stack.\n  FBASSERT(!currentScope());\n  g_vm->DetachCurrentThread();\n}\n\n/* static */\nJNIEnv* Environment::ensureCurrentThreadIsAttached() {\n\n  JNIEnv* env;\n  // We should be able to just get the JNIEnv* by just calling\n  // AttachCurrentThread, but the spec is unclear (and using getEnv is probably\n  // generally more reliable).\n  auto result = getEnv(&env);\n  // We don't know how to deal with anything other than JNI_OK or JNI_DETACHED.\n  FBASSERT(result == JNI_OK || result == JNI_EDETACHED);\n  if (result == JNI_EDETACHED) {\n    // The thread should not be detached while a ThreadScope is in the stack.\n    env = attachCurrentThread();\n  }\n  FBASSERT(env);\n  return env;\n}\n\nThreadScope::ThreadScope() : ThreadScope(nullptr, internal::CacheEnvTag{}) {}\n\nThreadScope::ThreadScope(JNIEnv* env, internal::CacheEnvTag)\n    : previous_(nullptr), env_(nullptr), attachedWithThisScope_(false) {\n  auto& storage = scopeStorage();\n  previous_ = storage.get();\n  storage.reset(this);\n\n  if (previous_ && previous_->env_) {\n    FBASSERT(!env || env == previous_->env_);\n    env = previous_->env_;\n  }\n\n  env_ = env;\n  if (env_) {\n    return;\n  }\n\n  // Check if the thread is attached by someone else.\n  auto result = getEnv(&env);\n  if (result == JNI_OK) {\n    return;\n  }\n\n  // We don't know how to deal with anything other than JNI_OK or JNI_DETACHED.\n  FBASSERT(result == JNI_EDETACHED);\n\n  // If there's already a ThreadScope on the stack, then the thread should be attached.\n  FBASSERT(!previous_);\n  attachCurrentThread();\n  attachedWithThisScope_ = true;\n}\n\nThreadScope::~ThreadScope() {\n  auto& storage = scopeStorage();\n  // ThreadScopes should be destroyed in the reverse order they are created\n  // (that is, just put them on the stack).\n  FBASSERT(this == storage.get());\n  storage.reset(previous_);\n  if (attachedWithThisScope_) {\n    Environment::detachCurrentThread();\n  }\n}\n\nnamespace {\nstruct JThreadScopeSupport : JavaClass<JThreadScopeSupport> {\n  static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/ThreadScopeSupport;\";\n\n  // These reinterpret_casts are a totally dangerous pattern. Don't use them. Use HybridData instead.\n  static void runStdFunction(std::function<void()>&& func) {\n    static auto method = javaClassStatic()->getStaticMethod<void(jlong)>(\"runStdFunction\");\n    method(javaClassStatic(), reinterpret_cast<jlong>(&func));\n  }\n\n  static void runStdFunctionImpl(alias_ref<JClass>, jlong ptr) {\n    (*reinterpret_cast<std::function<void()>*>(ptr))();\n  }\n\n  static void OnLoad() {\n    // We need the javaClassStatic so that the class lookup is cached and that\n    // runStdFunction can be called from a ThreadScope-attached thread.\n    javaClassStatic()->registerNatives({\n        makeNativeMethod(\"runStdFunctionImpl\", runStdFunctionImpl),\n      });\n  }\n};\n}\n\n/* static */\nvoid ThreadScope::OnLoad() {\n  // These classes are required for ScopeWithClassLoader. Ensure they are looked up when loading.\n  JThreadScopeSupport::OnLoad();\n}\n\n/* static */\nvoid ThreadScope::WithClassLoader(std::function<void()>&& runnable) {\n  // TODO(cjhopman): If the classloader is already available in this scope, we\n  // shouldn't have to jump through java. It should be enough to check if the\n  // attach state env* is set.\n  ThreadScope ts;\n  JThreadScopeSupport::runStdFunction(std::move(runnable));\n}\n\n} }\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/Exceptions.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/fbjni/CoreClasses.h>\n\n#include <fb/assert.h>\n#include <fb/log.h>\n\n#ifdef USE_LYRA\n#include <fb/lyra.h>\n#include <fb/lyra_exceptions.h>\n#endif\n\n#include <alloca.h>\n#include <cstdlib>\n#include <ios>\n#include <stdexcept>\n#include <stdio.h>\n#include <string>\n#include <system_error>\n\n#include <jni.h>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace {\nclass JRuntimeException : public JavaClass<JRuntimeException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/RuntimeException;\";\n\n  static local_ref<JRuntimeException> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n\n  static local_ref<JRuntimeException> create() {\n    return newInstance();\n  }\n};\n\nclass JIOException : public JavaClass<JIOException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Ljava/io/IOException;\";\n\n  static local_ref<JIOException> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n};\n\nclass JOutOfMemoryError : public JavaClass<JOutOfMemoryError, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/OutOfMemoryError;\";\n\n  static local_ref<JOutOfMemoryError> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n};\n\nclass JArrayIndexOutOfBoundsException : public JavaClass<JArrayIndexOutOfBoundsException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Ljava/lang/ArrayIndexOutOfBoundsException;\";\n\n  static local_ref<JArrayIndexOutOfBoundsException> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n};\n\nclass JUnknownCppException : public JavaClass<JUnknownCppException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/UnknownCppException;\";\n\n  static local_ref<JUnknownCppException> create() {\n    return newInstance();\n  }\n\n  static local_ref<JUnknownCppException> create(const char* str) {\n    return newInstance(make_jstring(str));\n  }\n};\n\nclass JCppSystemErrorException : public JavaClass<JCppSystemErrorException, JThrowable> {\n public:\n  static auto constexpr kJavaDescriptor = \"Lcom/facebook/jni/CppSystemErrorException;\";\n\n  static local_ref<JCppSystemErrorException> create(const std::system_error& e) {\n    return newInstance(make_jstring(e.what()), e.code().value());\n  }\n};\n\n// Exception throwing & translating functions //////////////////////////////////////////////////////\n\n// Functions that throw Java exceptions\n\nvoid setJavaExceptionAndAbortOnFailure(alias_ref<JThrowable> throwable) {\n  auto env = Environment::current();\n  if (throwable) {\n    env->Throw(throwable.get());\n  }\n  if (env->ExceptionCheck() != JNI_TRUE) {\n    std::abort();\n  }\n}\n\n}\n\n// Functions that throw C++ exceptions\n\n// TODO(T6618159) Inject the c++ stack into the exception's stack trace. One\n// issue: when a java exception is created, it captures the full java stack\n// across jni boundaries. lyra will only capture the c++ stack to the jni\n// boundary. So, as we pass the java exception up to c++, we need to capture\n// the c++ stack and then insert it into the correct place in the java stack\n// trace. Then, as the exception propagates across the boundaries, we will\n// slowly fill in the c++ parts of the trace.\nvoid throwPendingJniExceptionAsCppException() {\n  JNIEnv* env = Environment::current();\n  if (env->ExceptionCheck() == JNI_FALSE) {\n    return;\n  }\n\n  auto throwable = adopt_local(env->ExceptionOccurred());\n  if (!throwable) {\n    throw std::runtime_error(\"Unable to get pending JNI exception.\");\n  }\n  env->ExceptionClear();\n\n  throw JniException(throwable);\n}\n\nvoid throwCppExceptionIf(bool condition) {\n  if (!condition) {\n    return;\n  }\n\n  auto env = Environment::current();\n  if (env->ExceptionCheck() == JNI_TRUE) {\n    throwPendingJniExceptionAsCppException();\n    return;\n  }\n\n  throw JniException();\n}\n\nvoid throwNewJavaException(jthrowable throwable) {\n  throw JniException(wrap_alias(throwable));\n}\n\nvoid throwNewJavaException(const char* throwableName, const char* msg) {\n  // If anything of the fbjni calls fail, an exception of a suitable\n  // form will be thrown, which is what we want.\n  auto throwableClass = findClassLocal(throwableName);\n  auto throwable = throwableClass->newObject(\n    throwableClass->getConstructor<jthrowable(jstring)>(),\n    make_jstring(msg).release());\n  throwNewJavaException(throwable.get());\n}\n\n// jthrowable //////////////////////////////////////////////////////////////////////////////////////\n\nlocal_ref<JThrowable> JThrowable::initCause(alias_ref<JThrowable> cause) {\n  static auto meth = javaClassStatic()->getMethod<javaobject(alias_ref<javaobject>)>(\"initCause\");\n  return meth(self(), cause);\n}\n\nauto JThrowable::getStackTrace() -> local_ref<JStackTrace> {\n  static auto meth = javaClassStatic()->getMethod<JStackTrace::javaobject()>(\"getStackTrace\");\n  return meth(self());\n}\n\nvoid JThrowable::setStackTrace(alias_ref<JStackTrace> stack) {\n  static auto meth = javaClassStatic()->getMethod<void(alias_ref<JStackTrace>)>(\"setStackTrace\");\n  return meth(self(), stack);\n}\n\nauto JStackTraceElement::create(\n    const std::string& declaringClass, const std::string& methodName, const std::string& file, int line)\n    -> local_ref<javaobject> {\n  return newInstance(declaringClass, methodName, file, line);\n}\n\nstd::string JStackTraceElement::getClassName() const {\n  static auto meth = javaClassStatic()->getMethod<local_ref<JString>()>(\"getClassName\");\n  return meth(self())->toStdString();\n}\n\nstd::string JStackTraceElement::getMethodName() const {\n  static auto meth = javaClassStatic()->getMethod<local_ref<JString>()>(\"getMethodName\");\n  return meth(self())->toStdString();\n}\n\nstd::string JStackTraceElement::getFileName() const {\n  static auto meth = javaClassStatic()->getMethod<local_ref<JString>()>(\"getFileName\");\n  return meth(self())->toStdString();\n}\n\nint JStackTraceElement::getLineNumber() const {\n  static auto meth = javaClassStatic()->getMethod<jint()>(\"getLineNumber\");\n  return meth(self());\n}\n\n// Translate C++ to Java Exception\n\nnamespace {\n\n// For each exception in the chain of the exception_ptr argument, func\n// will be called with that exception (in reverse order, i.e. innermost first).\n#ifndef FBJNI_NO_EXCEPTION_PTR\nvoid denest(const std::function<void(std::exception_ptr)>& func, std::exception_ptr ptr) {\n  FBASSERT(ptr);\n  try {\n    std::rethrow_exception(ptr);\n  } catch (const std::nested_exception& e) {\n    denest(func, e.nested_ptr());\n  } catch (...) {\n    // ignored.\n  }\n  func(ptr);\n  }\n#endif\n\n} // namespace\n\n\n#ifdef USE_LYRA\nlocal_ref<JStackTraceElement> createJStackTraceElement(const lyra::StackTraceElement& cpp) {\n  return JStackTraceElement::create(\n      \"|lyra|{\" + cpp.libraryName() + \"}\", cpp.functionName(), cpp.buildId(), cpp.libraryOffset());\n}\n#endif\n\n#ifndef FBJNI_NO_EXCEPTION_PTR\nvoid addCppStacktraceToJavaException(alias_ref<JThrowable> java, std::exception_ptr cpp) {\n#ifdef USE_LYRA\n  auto cppStack = lyra::getStackTraceSymbols(\n                    (cpp == nullptr) ?\n                      lyra::getStackTrace()\n                      : lyra::getExceptionTrace(cpp));\n\n  auto javaStack = java->getStackTrace();\n  auto newStack = JThrowable::JStackTrace::newArray(javaStack->size() + cppStack.size());\n  size_t i = 0;\n  for (size_t j = 0; j < cppStack.size(); j++, i++) {\n    (*newStack)[i] = createJStackTraceElement(cppStack[j]);\n  }\n  for (size_t j = 0; j < javaStack->size(); j++, i++) {\n    (*newStack)[i] = (*javaStack)[j];\n  }\n  java->setStackTrace(newStack);\n#endif\n}\n\nlocal_ref<JThrowable> convertCppExceptionToJavaException(std::exception_ptr ptr) {\n  FBASSERT(ptr);\n  local_ref<JThrowable> current;\n  bool addCppStack = true;\n  try {\n    std::rethrow_exception(ptr);\n    addCppStack = false;\n  } catch (const JniException& ex) {\n    current = ex.getThrowable();\n  } catch (const std::ios_base::failure& ex) {\n    current = JIOException::create(ex.what());\n  } catch (const std::bad_alloc& ex) {\n    current = JOutOfMemoryError::create(ex.what());\n  } catch (const std::out_of_range& ex) {\n    current = JArrayIndexOutOfBoundsException::create(ex.what());\n  } catch (const std::system_error& ex) {\n    current = JCppSystemErrorException::create(ex);\n  } catch (const std::runtime_error& ex) {\n    current = JRuntimeException::create(ex.what());\n  } catch (const std::exception& ex) {\n    current = JCppException::create(ex.what());\n  } catch (const char* msg) {\n    current = JUnknownCppException::create(msg);\n  } catch (...) {\n    current = JUnknownCppException::create();\n  }\n\n  if (addCppStack) {\n    addCppStacktraceToJavaException(current, ptr);\n  }\n  return current;\n  }\n#endif\n\nlocal_ref<JThrowable> getJavaExceptionForCppBackTrace() {\n  return getJavaExceptionForCppBackTrace(nullptr);\n}\n\nlocal_ref<JThrowable> getJavaExceptionForCppBackTrace(const char* msg) {\n  local_ref<JThrowable> current =\n      msg ? JUnknownCppException::create(msg) : JUnknownCppException::create();\n#ifndef FBJNI_NO_EXCEPTION_PTR\n  addCppStacktraceToJavaException(current, nullptr);\n#endif\n  return current;\n}\n\n\n#ifndef FBJNI_NO_EXCEPTION_PTR\nlocal_ref<JThrowable> getJavaExceptionForCppException(std::exception_ptr ptr) {\n  FBASSERT(ptr);\n  local_ref<JThrowable> previous;\n  auto func = [&previous] (std::exception_ptr ptr) {\n    auto current = convertCppExceptionToJavaException(ptr);\n    if (previous) {\n      current->initCause(previous);\n    }\n    previous = current;\n  };\n  denest(func, ptr);\n  return previous;\n}\n#endif\n\nvoid translatePendingCppExceptionToJavaException() {\n  try {\n#ifndef FBJNI_NO_EXCEPTION_PTR\n    auto exc = getJavaExceptionForCppException(std::current_exception());\n#else\n    auto exc = JUnknownCppException::create();\n#endif\n    setJavaExceptionAndAbortOnFailure(exc);\n  } catch (...) {\n#ifdef USE_LYRA\n    FBLOGE(\"Unexpected error in translatePendingCppExceptionToJavaException(): %s\",\n        lyra::toString(std::current_exception()).c_str());\n#endif\n    std::terminate();\n  }\n}\n\n// JniException ////////////////////////////////////////////////////////////////////////////////////\n\nconst std::string JniException::kExceptionMessageFailure_ = \"Unable to get exception message.\";\n\nJniException::JniException() : JniException(JRuntimeException::create()) { }\n\nJniException::JniException(alias_ref<jthrowable> throwable) : isMessageExtracted_(false) {\n  throwable_ = make_global(throwable);\n}\n\nJniException::JniException(JniException &&rhs)\n    : throwable_(std::move(rhs.throwable_)),\n      what_(std::move(rhs.what_)),\n      isMessageExtracted_(rhs.isMessageExtracted_) {\n}\n\nJniException::JniException(const JniException &rhs)\n    : what_(rhs.what_), isMessageExtracted_(rhs.isMessageExtracted_) {\n  throwable_ = make_global(rhs.throwable_);\n}\n\nJniException::~JniException() {\n  try {\n    ThreadScope ts;\n    throwable_.reset();\n  } catch (...) {\n    FBLOGE(\"Exception in ~JniException()\");\n    std::terminate();\n  }\n}\n\nlocal_ref<JThrowable> JniException::getThrowable() const noexcept {\n  return make_local(throwable_);\n}\n\n// TODO 6900503: consider making this thread-safe.\nvoid JniException::populateWhat() const noexcept {\n  try {\n    ThreadScope ts;\n    what_ = throwable_->toString();\n    isMessageExtracted_ = true;\n  } catch(...) {\n    what_ = kExceptionMessageFailure_;\n  }\n}\n\nconst char* JniException::what() const noexcept {\n  if (!isMessageExtracted_) {\n    populateWhat();\n  }\n  return what_.c_str();\n}\n\nvoid JniException::setJavaException() const noexcept {\n  setJavaExceptionAndAbortOnFailure(throwable_);\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/Hybrid.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include \"fb/fbjni.h\"\n\n\nnamespace facebook {\nnamespace jni {\n\nnamespace detail {\n\nlocal_ref<HybridData> HybridData::create() {\n  return newInstance();\n}\n\n}\n\nnamespace {\nvoid deleteNative(alias_ref<jclass>, jlong ptr) {\n  delete reinterpret_cast<detail::BaseHybridClass*>(ptr);\n}\n}\n\nvoid HybridDataOnLoad() {\n  registerNatives(\"com/facebook/jni/HybridData$Destructor\", {\n      makeNativeMethod(\"deleteNative\", deleteNative),\n  });\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/LocalString.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <jni/LocalString.h>\n#include <fb/Environment.h>\n#include <fb/assert.h>\n\n#include <vector>\n\nnamespace facebook {\nnamespace jni {\n\nnamespace {\n\nconst uint16_t kUtf8OneByteBoundary       = 0x80;\nconst uint16_t kUtf8TwoBytesBoundary      = 0x800;\nconst uint16_t kUtf16HighSubLowBoundary   = 0xD800;\nconst uint16_t kUtf16HighSubHighBoundary  = 0xDC00;\nconst uint16_t kUtf16LowSubHighBoundary   = 0xE000;\n\ninline void encode3ByteUTF8(char32_t code, uint8_t* out) {\n  FBASSERTMSGF((code & 0xffff0000) == 0, \"3 byte utf-8 encodings only valid for up to 16 bits\");\n\n  out[0] = 0xE0 | (code >> 12);\n  out[1] = 0x80 | ((code >> 6) & 0x3F);\n  out[2] = 0x80 | (code & 0x3F);\n}\n\ninline char32_t decode3ByteUTF8(const uint8_t* in) {\n  return (((in[0] & 0x0f) << 12) |\n          ((in[1] & 0x3f) << 6) |\n          ( in[2] & 0x3f));\n}\n\ninline void encode4ByteUTF8(char32_t code, std::string& out, size_t offset) {\n  FBASSERTMSGF((code & 0xfff80000) == 0, \"4 byte utf-8 encodings only valid for up to 21 bits\");\n\n  out[offset] =     (char) (0xF0 | (code >> 18));\n  out[offset + 1] = (char) (0x80 | ((code >> 12) & 0x3F));\n  out[offset + 2] = (char) (0x80 | ((code >> 6) & 0x3F));\n  out[offset + 3] = (char) (0x80 | (code & 0x3F));\n}\n\ntemplate <typename T>\ninline bool isFourByteUTF8Encoding(const T* utf8) {\n  return ((*utf8 & 0xF8) == 0xF0);\n}\n\n}\n\nnamespace detail {\n\nsize_t modifiedLength(const std::string& str) {\n  // Scan for supplementary characters\n  size_t j = 0;\n  for (size_t i = 0; i < str.size(); ) {\n    if (str[i] == 0) {\n      i += 1;\n      j += 2;\n    } else if (i + 4 > str.size() ||\n               !isFourByteUTF8Encoding(&(str[i]))) {\n      // See the code in utf8ToModifiedUTF8 for what's happening here.\n      i += 1;\n      j += 1;\n    } else {\n      i += 4;\n      j += 6;\n    }\n  }\n\n  return j;\n}\n\n// returns modified utf8 length; *length is set to strlen(str)\nsize_t modifiedLength(const uint8_t* str, size_t* length) {\n  // NUL-terminated: Scan for length and supplementary characters\n  size_t i = 0;\n  size_t j = 0;\n  if (str != nullptr) {\n    while (str[i] != 0) {\n      if (str[i + 1] == 0 ||\n          str[i + 2] == 0 ||\n          str[i + 3] == 0 ||\n          !isFourByteUTF8Encoding(&(str[i]))) {\n        i += 1;\n        j += 1;\n      } else {\n        i += 4;\n        j += 6;\n      }\n    }\n  }\n\n  *length = i;\n  return j;\n}\n\nvoid utf8ToModifiedUTF8(const uint8_t* utf8, size_t len, uint8_t* modified, size_t modifiedBufLen)\n{\n  size_t j = 0;\n  for (size_t i = 0; i < len; ) {\n    FBASSERTMSGF(j < modifiedBufLen, \"output buffer is too short\");\n    if (utf8[i] == 0) {\n      FBASSERTMSGF(j + 1 < modifiedBufLen, \"output buffer is too short\");\n      modified[j] = 0xc0;\n      modified[j + 1] = 0x80;\n      i += 1;\n      j += 2;\n      continue;\n    }\n\n    if (i + 4 > len ||\n        !isFourByteUTF8Encoding(utf8 + i)) {\n      // If the input is too short for this to be a four-byte\n      // encoding, or it isn't one for real, just copy it on through.\n      modified[j] = utf8[i];\n      i++;\n      j++;\n      continue;\n    }\n\n    // Convert 4 bytes of input to 2 * 3 bytes of output\n    char32_t code = (((utf8[i]     & 0x07) << 18) |\n                     ((utf8[i + 1] & 0x3f) << 12) |\n                     ((utf8[i + 2] & 0x3f) << 6) |\n                     ( utf8[i + 3] & 0x3f));\n    char32_t first;\n    char32_t second;\n\n    if (code > 0x10ffff) {\n      // These could be valid utf-8, but cannot be represented as modified UTF-8, due to the 20-bit\n      // limit on that representation.  Encode two replacement characters, so the expected output\n      // length lines up.\n      const char32_t kUnicodeReplacementChar = 0xfffd;\n      first = kUnicodeReplacementChar;\n      second = kUnicodeReplacementChar;\n    } else {\n      // split into surrogate pair\n      first = ((code - 0x010000) >> 10) | 0xd800;\n      second = ((code - 0x010000) & 0x3ff) | 0xdc00;\n    }\n\n    // encode each as a 3 byte surrogate value\n    FBASSERTMSGF(j + 5 < modifiedBufLen, \"output buffer is too short\");\n    encode3ByteUTF8(first, modified + j);\n    encode3ByteUTF8(second, modified + j + 3);\n    i += 4;\n    j += 6;\n  }\n\n  FBASSERTMSGF(j < modifiedBufLen, \"output buffer is too short\");\n  modified[j++] = '\\0';\n}\n\nstd::string modifiedUTF8ToUTF8(const uint8_t* modified, size_t len) noexcept {\n  // Converting from modified utf8 to utf8 will always shrink, so this will always be sufficient\n  std::string utf8(len, 0);\n  size_t j = 0;\n  for (size_t i = 0; i < len; ) {\n    // surrogate pair: 1101 10xx  xxxx xxxx  1101 11xx  xxxx xxxx\n    // encoded pair: 1110 1101  1010 xxxx  10xx xxxx  1110 1101  1011 xxxx  10xx xxxx\n\n    if (len >= i + 6 &&\n        modified[i] == 0xed &&\n        (modified[i + 1] & 0xf0) == 0xa0 &&\n        modified[i + 3] == 0xed &&\n        (modified[i + 4] & 0xf0) == 0xb0) {\n      // Valid surrogate pair\n      char32_t pair1 = decode3ByteUTF8(modified + i);\n      char32_t pair2 = decode3ByteUTF8(modified + i + 3);\n      char32_t ch = 0x10000 + (((pair1 & 0x3ff) << 10) |\n                               ( pair2 & 0x3ff));\n      encode4ByteUTF8(ch, utf8, j);\n      i += 6;\n      j += 4;\n      continue;\n    } else if (len >= i + 2 &&\n               modified[i] == 0xc0 &&\n               modified[i + 1] == 0x80) {\n      utf8[j] = 0;\n      i += 2;\n      j += 1;\n      continue;\n    }\n\n    // copy one byte.  This might be a one, two, or three-byte encoding.  It might be an invalid\n    // encoding of some sort, but garbage in garbage out is ok.\n\n    utf8[j] = (char) modified[i];\n    i++;\n    j++;\n  }\n\n  utf8.resize(j);\n\n  return utf8;\n}\n\n// Calculate how many bytes are needed to convert an UTF16 string into UTF8\n// UTF16 string\nsize_t utf16toUTF8Length(const uint16_t* utf16String, size_t utf16StringLen) {\n  if (!utf16String || utf16StringLen == 0) {\n    return 0;\n  }\n\n  uint32_t utf8StringLen = 0;\n  auto utf16StringEnd = utf16String + utf16StringLen;\n  auto idx16 = utf16String;\n  while (idx16 < utf16StringEnd) {\n    auto ch = *idx16++;\n    if (ch < kUtf8OneByteBoundary) {\n      utf8StringLen++;\n    } else if (ch < kUtf8TwoBytesBoundary) {\n      utf8StringLen += 2;\n    } else if (\n        (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&\n        (idx16 < utf16StringEnd) &&\n        (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {\n      utf8StringLen += 4;\n      idx16++;\n    } else {\n      utf8StringLen += 3;\n    }\n  }\n\n  return utf8StringLen;\n}\n\nstd::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) noexcept {\n  if (!utf16String || utf16StringLen <= 0) {\n    return \"\";\n  }\n\n  std::string utf8String(utf16toUTF8Length(utf16String, utf16StringLen), '\\0');\n  auto idx8 = utf8String.begin();\n  auto idx16 = utf16String;\n  auto utf16StringEnd = utf16String + utf16StringLen;\n  while (idx16 < utf16StringEnd) {\n    auto ch = *idx16++;\n    if (ch < kUtf8OneByteBoundary) {\n      *idx8++ = (ch & 0x7F);\n    } else if (ch < kUtf8TwoBytesBoundary) {\n      *idx8++ = 0b11000000 | (ch >> 6);\n      *idx8++ = 0b10000000 | (ch & 0x3F);\n    } else if (\n        (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&\n        (idx16 < utf16StringEnd) &&\n        (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {\n      auto ch2 = *idx16++;\n      uint8_t trunc_byte = (((ch >> 6) & 0x0F) + 1);\n      *idx8++ = 0b11110000 | (trunc_byte >> 2);\n      *idx8++ = 0b10000000 | ((trunc_byte & 0x03) << 4) | ((ch >> 2) & 0x0F);\n      *idx8++ = 0b10000000 | ((ch & 0x03) << 4) | ((ch2 >> 6) & 0x0F);\n      *idx8++ = 0b10000000 | (ch2 & 0x3F);\n    } else {\n      *idx8++ = 0b11100000 | (ch >> 12);\n      *idx8++ = 0b10000000 | ((ch >> 6) & 0x3F);\n      *idx8++ = 0b10000000 | (ch & 0x3F);\n    }\n  }\n\n  return utf8String;\n}\n\n}\n\nLocalString::LocalString(const std::string& str)\n{\n  size_t modlen = detail::modifiedLength(str);\n  if (modlen == str.size()) {\n    // no supplementary characters, build jstring from input buffer\n    m_string = Environment::current()->NewStringUTF(str.data());\n    return;\n  }\n  auto modified = std::vector<char>(modlen + 1); // allocate extra byte for \\0\n  detail::utf8ToModifiedUTF8(\n    reinterpret_cast<const uint8_t*>(str.data()), str.size(),\n    reinterpret_cast<uint8_t*>(modified.data()), modified.size());\n  m_string = Environment::current()->NewStringUTF(modified.data());\n}\n\nLocalString::LocalString(const char* str)\n{\n  size_t len;\n  size_t modlen = detail::modifiedLength(reinterpret_cast<const uint8_t*>(str), &len);\n  if (modlen == len) {\n    // no supplementary characters, build jstring from input buffer\n    m_string = Environment::current()->NewStringUTF(str);\n    return;\n  }\n  auto modified = std::vector<char>(modlen + 1); // allocate extra byte for \\0\n  detail::utf8ToModifiedUTF8(\n    reinterpret_cast<const uint8_t*>(str), len,\n    reinterpret_cast<uint8_t*>(modified.data()), modified.size());\n  m_string = Environment::current()->NewStringUTF(modified.data());\n}\n\nLocalString::~LocalString() {\n  Environment::current()->DeleteLocalRef(m_string);\n}\n\nstd::string fromJString(JNIEnv* env, jstring str) {\n  auto utf16String = JStringUtf16Extractor(env, str);\n  return detail::utf16toUTF8(utf16String.chars(), utf16String.length());\n}\n\n} }\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/OnLoad.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <jni/Countable.h>\n#include <fb/Environment.h>\n#include <fb/fbjni.h>\n#include <fb/fbjni/NativeRunnable.h>\n\nusing namespace facebook::jni;\n\nvoid initialize_fbjni() {\n  CountableOnLoad(Environment::current());\n  HybridDataOnLoad();\n  JNativeRunnable::OnLoad();\n  ThreadScope::OnLoad();\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/References.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/fbjni/References.h>\n\nnamespace facebook {\nnamespace jni {\n\nJniLocalScope::JniLocalScope(JNIEnv* env, jint capacity)\n    : env_(env) {\n  hasFrame_ = false;\n  auto pushResult = env->PushLocalFrame(capacity);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(pushResult < 0);\n  hasFrame_ = true;\n}\n\nJniLocalScope::~JniLocalScope() {\n  if (hasFrame_) {\n    env_->PopLocalFrame(nullptr);\n  }\n}\n\nnamespace internal {\n\n// Default implementation always returns true.\n// Platform-specific sources can override this.\nbool doesGetObjectRefTypeWork() __attribute__ ((weak));\nbool doesGetObjectRefTypeWork() {\n  return true;\n}\n\n}\n\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/WeakReference.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/Environment.h>\n#include <jni/WeakReference.h>\n\nnamespace facebook {\nnamespace jni {\n\nWeakReference::WeakReference(jobject strongRef) :\n  m_weakReference(Environment::current()->NewWeakGlobalRef(strongRef))\n{\n}\n\nWeakReference::~WeakReference() {\n  auto env = Environment::current();\n  FBASSERTMSGF(env, \"Attempt to delete jni::WeakReference from non-JNI thread\");\n  env->DeleteWeakGlobalRef(m_weakReference);\n}\n\nResolvedWeakReference::ResolvedWeakReference(jobject weakRef) :\n  m_strongReference(Environment::current()->NewLocalRef(weakRef))\n{\n}\n\nResolvedWeakReference::ResolvedWeakReference(const RefPtr<WeakReference>& weakRef) :\n  m_strongReference(Environment::current()->NewLocalRef(weakRef->weakRef()))\n{\n}\n\nResolvedWeakReference::~ResolvedWeakReference() {\n  if (m_strongReference)\n    Environment::current()->DeleteLocalRef(m_strongReference);\n}\n\n} }\n\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/android/CpuCapabilities.cpp",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#include <fb/CpuCapabilities.h>\n#include <cpu-features.h>\n#include <fb/Environment.h>\n#include <glog/logging.h>\n#include <jni/Registration.h>\n\nnamespace facebook { namespace jni {\n\n// =========================================\n// returns true if this device supports NEON calls, false otherwise\njboolean nativeDeviceSupportsNeon(JNIEnv* env, jobject obj) {\n  if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) {\n    VLOG(2) << \"NEON disabled, not an ARM CPU\";\n    return false;\n  }\n  uint64_t cpufeatures = android_getCpuFeatures();\n  if ((cpufeatures & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) {\n    VLOG(2) << \"NEON disabled, not an ARMv7 CPU\";\n    return false;\n  }\n  if ((cpufeatures & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {\n    VLOG(2) << \"NEON disabled, not supported\";\n    return false;\n  }\n\n  VLOG(2) << \"NEON supported and enabled\";\n  return true;\n}\n\n// =========================================\n// returns true if this device supports VFP_FP16, false otherwise.\njboolean nativeDeviceSupportsVFPFP16(JNIEnv *env, jobject obj) {\n  uint64_t cpufeatures = android_getCpuFeatures();\n  if ((cpufeatures & ANDROID_CPU_ARM_FEATURE_VFP_FP16) == 0) {\n    VLOG(2) << \"VPF_FP16 disabled, not supported\";\n    return false;\n  }\n  VLOG(2) << \"VFP_FP16 supported and enabled\";\n  return true;\n}\n\n// =========================================\n// returns true if this device is x86 based, false otherwise\njboolean nativeDeviceSupportsX86(JNIEnv* env, jobject obj) {\n  return (android_getCpuFamily() == ANDROID_CPU_FAMILY_X86);\n}\n\n// =========================================\n// register native methods\nvoid initialize_cpucapabilities() {\n  facebook::jni::registerNatives(\n      Environment::current(),\n      \"com/facebook/jni/CpuCapabilitiesJni\",\n      {\n        { \"nativeDeviceSupportsNeon\",\n          \"()Z\",\n          (void*) nativeDeviceSupportsNeon },\n        { \"nativeDeviceSupportsVFPFP16\",\n          \"()Z\",\n          (void*) nativeDeviceSupportsVFPFP16 },\n        { \"nativeDeviceSupportsX86\",\n          \"()Z\",\n          (void*) nativeDeviceSupportsX86 },\n      }\n  );\n}\n\n} } // namespace facebook::jni\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/android/ReferenceChecking.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#ifndef __ANDROID__\n#error \"This file should only be compiled for Android.\"\n#endif\n\n#include <fb/fbjni/References.h>\n#include <fb/fbjni/CoreClasses.h>\n\nnamespace facebook {\nnamespace jni {\nnamespace internal {\n\nstatic int32_t getApiLevel() {\n  auto cls = findClassLocal(\"android/os/Build$VERSION\");\n  auto fld = cls->getStaticField<int32_t>(\"SDK_INT\");\n  if (fld) {\n    return cls->getStaticFieldValue(fld);\n  }\n  return 0;\n}\n\nbool doesGetObjectRefTypeWork() {\n  static auto level = getApiLevel();\n  return level >= 14;\n}\n\n}\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/fbjni.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/fbjni.h>\n\n#include <mutex>\n#include <vector>\n#include <jni/LocalString.h>\n#include <fb/log.h>\n\nnamespace facebook {\nnamespace jni {\n\njint initialize(JavaVM* vm, std::function<void()>&& init_fn) noexcept {\n  static std::once_flag flag{};\n  // TODO (t7832883): DTRT when we have exception pointers\n  static auto error_msg = std::string{\"Failed to initialize fbjni\"};\n  static auto error_occured = false;\n\n  std::call_once(flag, [vm] {\n    try {\n      Environment::initialize(vm);\n    } catch (std::exception& ex) {\n      error_occured = true;\n      try {\n        error_msg = std::string{\"Failed to initialize fbjni: \"} + ex.what();\n      } catch (...) {\n        // Ignore, we already have a fall back message\n      }\n    } catch (...) {\n      error_occured = true;\n    }\n  });\n\n  try {\n    if (error_occured) {\n      throw std::runtime_error(error_msg);\n    }\n\n    init_fn();\n  } catch (const std::exception& e) {\n    FBLOGE(\"error %s\", e.what());\n    translatePendingCppExceptionToJavaException();\n  } catch (...) {\n    translatePendingCppExceptionToJavaException();\n    // So Java will handle the translated exception, fall through and\n    // return a good version number.\n  }\n  return JNI_VERSION_1_6;\n}\n\nalias_ref<JClass> findClassStatic(const char* name) {\n  const auto env = internal::getEnv();\n  if (!env) {\n    throw std::runtime_error(\"Unable to retrieve JNIEnv*.\");\n  }\n  local_ref<jclass> cls = adopt_local(env->FindClass(name));\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!cls);\n  auto leaking_ref = (jclass)env->NewGlobalRef(cls.get());\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!leaking_ref);\n  return wrap_alias(leaking_ref);\n}\n\nlocal_ref<JClass> findClassLocal(const char* name) {\n  const auto env = internal::getEnv();\n  if (!env) {\n    throw std::runtime_error(\"Unable to retrieve JNIEnv*.\");\n  }\n  auto cls = env->FindClass(name);\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!cls);\n  return adopt_local(cls);\n}\n\n\n// jstring /////////////////////////////////////////////////////////////////////////////////////////\n\nstd::string JString::toStdString() const {\n  const auto env = internal::getEnv();\n  auto utf16String = JStringUtf16Extractor(env, self());\n  return detail::utf16toUTF8(utf16String.chars(), utf16String.length());\n}\n\nlocal_ref<JString> make_jstring(const char* utf8) {\n  if (!utf8) {\n    return {};\n  }\n  const auto env = internal::getEnv();\n  size_t len;\n  size_t modlen = detail::modifiedLength(reinterpret_cast<const uint8_t*>(utf8), &len);\n  jstring result;\n  if (modlen == len) {\n    // The only difference between utf8 and modifiedUTF8 is in encoding 4-byte UTF8 chars\n    // and '\\0' that is encoded on 2 bytes.\n    //\n    // Since modifiedUTF8-encoded string can be no shorter than it's UTF8 conterpart we\n    // know that if those two strings are of the same length we don't need to do any\n    // conversion -> no 4-byte chars nor '\\0'.\n    result = env->NewStringUTF(utf8);\n  } else {\n    auto modified = std::vector<char>(modlen + 1); // allocate extra byte for \\0\n    detail::utf8ToModifiedUTF8(\n      reinterpret_cast<const uint8_t*>(utf8), len,\n      reinterpret_cast<uint8_t*>(modified.data()), modified.size());\n    result = env->NewStringUTF(modified.data());\n  }\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();\n  return adopt_local(result);\n}\n\n\n// JniPrimitiveArrayFunctions //////////////////////////////////////////////////////////////////////\n\n#pragma push_macro(\"DEFINE_PRIMITIVE_METHODS\")\n#undef DEFINE_PRIMITIVE_METHODS\n#define DEFINE_PRIMITIVE_METHODS(TYPE, NAME, SMALLNAME)                        \\\n                                                                               \\\ntemplate<>                                                                     \\\nFBEXPORT                                                                       \\\nTYPE* JPrimitiveArray<TYPE ## Array>::getElements(jboolean* isCopy) {          \\\n  auto env = internal::getEnv();                                               \\\n  TYPE* res =  env->Get ## NAME ## ArrayElements(self(), isCopy);              \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \\\n  return res;                                                                  \\\n}                                                                              \\\n                                                                               \\\ntemplate<>                                                                     \\\nFBEXPORT                                                                       \\\nvoid JPrimitiveArray<TYPE ## Array>::releaseElements(                          \\\n    TYPE* elements, jint mode) {                                               \\\n  auto env = internal::getEnv();                                               \\\n  env->Release ## NAME ## ArrayElements(self(), elements, mode);               \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \\\n}                                                                              \\\n                                                                               \\\ntemplate<>                                                                     \\\nFBEXPORT                                                                       \\\nvoid JPrimitiveArray<TYPE ## Array>::getRegion(                                \\\n    jsize start, jsize length, TYPE* buf) {                                    \\\n  auto env = internal::getEnv();                                               \\\n  env->Get ## NAME ## ArrayRegion(self(), start, length, buf);                 \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \\\n}                                                                              \\\n                                                                               \\\ntemplate<>                                                                     \\\nFBEXPORT                                                                       \\\nvoid JPrimitiveArray<TYPE ## Array>::setRegion(                                \\\n    jsize start, jsize length, const TYPE* elements) {                         \\\n  auto env = internal::getEnv();                                               \\\n  env->Set ## NAME ## ArrayRegion(self(), start, length, elements);            \\\n  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \\\n}                                                                              \\\n                                                                               \\\nFBEXPORT                                                                       \\\nlocal_ref<TYPE ## Array> make_ ## SMALLNAME ## _array(jsize size) {            \\\n  auto array = internal::getEnv()->New ## NAME ## Array(size);                 \\\n  FACEBOOK_JNI_THROW_EXCEPTION_IF(!array);                                     \\\n  return adopt_local(array);                                                   \\\n}                                                                              \\\n                                                                               \\\ntemplate<>                                                                     \\\nFBEXPORT                                                                       \\\nlocal_ref<TYPE ## Array> JArray ## NAME::newArray(size_t count) {              \\\n  return make_ ## SMALLNAME ## _array(count);                                  \\\n}                                                                              \\\n                                                                               \\\n\nDEFINE_PRIMITIVE_METHODS(jboolean, Boolean, boolean)\nDEFINE_PRIMITIVE_METHODS(jbyte, Byte, byte)\nDEFINE_PRIMITIVE_METHODS(jchar, Char, char)\nDEFINE_PRIMITIVE_METHODS(jshort, Short, short)\nDEFINE_PRIMITIVE_METHODS(jint, Int, int)\nDEFINE_PRIMITIVE_METHODS(jlong, Long, long)\nDEFINE_PRIMITIVE_METHODS(jfloat, Float, float)\nDEFINE_PRIMITIVE_METHODS(jdouble, Double, double)\n#pragma pop_macro(\"DEFINE_PRIMITIVE_METHODS\")\n\n// Internal debug /////////////////////////////////////////////////////////////////////////////////\n\nnamespace internal {\n\nFBEXPORT ReferenceStats g_reference_stats;\n\nFBEXPORT void facebook::jni::internal::ReferenceStats::reset() noexcept {\n  locals_deleted = globals_deleted = weaks_deleted = 0;\n}\n\n}\n\n}}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/java/BUCK",
    "content": "include_defs(\"//ReactAndroid/DEFS\")\n\njava_library(\n    name = \"java\",\n    srcs = glob([\"**/*.java\"]),\n    visibility = [\"PUBLIC\"],\n    deps = [\n        \"//java/com/facebook/proguard/annotations:annotations\",\n    ],\n)\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/java/CppException.java",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\npackage fb.jni.java;\n\nimport com.facebook.proguard.annotations.DoNotStrip;\n\n@DoNotStrip\npublic class CppException extends RuntimeException {\n  @DoNotStrip\n  public CppException(String message) {\n    super(message);\n  }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/java/CppSystemErrorException.java",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\npackage fb.jni.java;\n\nimport com.facebook.proguard.annotations.DoNotStrip;\n\n@DoNotStrip\npublic class CppSystemErrorException extends CppException {\n  int errorCode;\n\n  @DoNotStrip\n  public CppSystemErrorException(String message, int errorCode) {\n    super(message);\n    this.errorCode = errorCode;\n  }\n\n  public int getErrorCode() {\n    return errorCode;\n  }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/java/UnknownCppException.java",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\npackage fb.jni.java;\n\nimport com.facebook.proguard.annotations.DoNotStrip;\n\n@DoNotStrip\npublic class UnknownCppException extends CppException {\n  @DoNotStrip\n  public UnknownCppException() {\n    super(\"Unknown\");\n  }\n\n  @DoNotStrip\n  public UnknownCppException(String message) {\n    super(message);\n  }\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/jni/jni_helpers.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <jni.h>\n#include <stddef.h>\n#include <cstdio>\n\n#include <jni/jni_helpers.h>\n\n#define MSG_SIZE 1024\n\nnamespace facebook {\n\n/**\n * Instructs the JNI environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param szClassName class name to throw\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwException(JNIEnv* pEnv, const char* szClassName, const char* szFmt, va_list va_args) {\n  char szMsg[MSG_SIZE];\n  vsnprintf(szMsg, MSG_SIZE, szFmt, va_args);\n  jclass exClass = pEnv->FindClass(szClassName);\n  return pEnv->ThrowNew(exClass, szMsg);\n}\n\n/**\n * Instructs the JNI environment to throw a NoClassDefFoundError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwNoClassDefError(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/NoClassDefFoundError\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw a RuntimeException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwRuntimeException(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/RuntimeException\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw an IllegalArgumentException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwIllegalArgumentException(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/IllegalArgumentException\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw an IllegalStateException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwIllegalStateException(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/IllegalStateException\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw an OutOfMemoryError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwOutOfMemoryError(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/OutOfMemoryError\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw an AssertionError.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwAssertionError(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/lang/AssertionError\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Instructs the JNI environment to throw an IOException.\n *\n * @param pEnv JNI environment\n * @param szFmt sprintf-style format string\n * @param ... sprintf-style args\n * @return 0 on success; a negative value on failure\n */\njint throwIOException(JNIEnv* pEnv, const char* szFmt, ...) {\n  va_list va_args;\n  va_start(va_args, szFmt);\n  jint ret = throwException(pEnv, \"java/io/IOException\", szFmt, va_args);\n  va_end(va_args);\n  return ret;\n}\n\n/**\n * Finds the specified class. If it's not found, instructs the JNI environment to throw an\n * exception.\n *\n * @param pEnv JNI environment\n * @param szClassName the classname to find in JNI format (e.g. \"java/lang/String\")\n * @return the class or NULL if not found (in which case a pending exception will be queued). This\n *     returns a global reference (JNIEnv::NewGlobalRef).\n */\njclass findClassOrThrow(JNIEnv* pEnv, const char* szClassName) {\n  jclass clazz = pEnv->FindClass(szClassName);\n  if (!clazz) {\n    return NULL;\n  }\n  return (jclass) pEnv->NewGlobalRef(clazz);\n}\n\n/**\n * Finds the specified field of the specified class. If it's not found, instructs the JNI\n * environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param clazz the class to lookup the field in\n * @param szFieldName the name of the field to find\n * @param szSig the signature of the field\n * @return the field or NULL if not found (in which case a pending exception will be queued)\n */\njfieldID getFieldIdOrThrow(JNIEnv* pEnv, jclass clazz, const char* szFieldName, const char* szSig) {\n  return pEnv->GetFieldID(clazz, szFieldName, szSig);\n}\n\n/**\n * Finds the specified method of the specified class. If it's not found, instructs the JNI\n * environment to throw an exception.\n *\n * @param pEnv JNI environment\n * @param clazz the class to lookup the method in\n * @param szMethodName the name of the method to find\n * @param szSig the signature of the method\n * @return the method or NULL if not found (in which case a pending exception will be queued)\n */\njmethodID getMethodIdOrThrow(\n    JNIEnv* pEnv,\n    jclass clazz,\n    const char* szMethodName,\n    const char* szSig) {\n  return pEnv->GetMethodID(clazz, szMethodName, szSig);\n}\n\n} // namespace facebook\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/log.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <fb/log.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <string.h>\n\n#define LOG_BUFFER_SIZE 4096\nstatic LogHandler gLogHandler;\n\nvoid setLogHandler(LogHandler logHandler) {\n  gLogHandler = logHandler;\n}\n\nint fb_printLog(int prio, const char *tag,  const char *fmt, ...) {\n  char logBuffer[LOG_BUFFER_SIZE];\n\n  va_list va_args;\n  va_start(va_args, fmt);\n  int result = vsnprintf(logBuffer, sizeof(logBuffer), fmt, va_args);\n  va_end(va_args);\n  if (gLogHandler != NULL) {\n      gLogHandler(prio, tag, logBuffer);\n  }\n  __android_log_write(prio, tag, logBuffer);\n  return result;\n}\n\nvoid logPrintByDelims(int priority, const char* tag, const char* delims,\n        const char* msg, ...)\n{\n    va_list ap;\n    char buf[32768];\n    char* context;\n    char* tok;\n\n    va_start(ap, msg);\n    vsnprintf(buf, sizeof(buf), msg, ap);\n    va_end(ap);\n\n    tok = strtok_r(buf, delims, &context);\n\n    if (!tok) {\n        return;\n    }\n\n    do {\n        __android_log_write(priority, tag, tok);\n    } while ((tok = strtok_r(NULL, delims, &context)));\n}\n\n#ifndef ANDROID\n\n// Implementations of the basic android logging functions for non-android platforms.\n\nstatic char logTagChar(int prio) {\n  switch (prio) {\n    default:\n    case ANDROID_LOG_UNKNOWN:\n    case ANDROID_LOG_DEFAULT:\n    case ANDROID_LOG_SILENT:\n      return ' ';\n    case ANDROID_LOG_VERBOSE:\n      return 'V';\n    case ANDROID_LOG_DEBUG:\n      return 'D';\n    case ANDROID_LOG_INFO:\n      return 'I';\n    case ANDROID_LOG_WARN:\n      return 'W';\n    case ANDROID_LOG_ERROR:\n      return 'E';\n    case ANDROID_LOG_FATAL:\n      return 'F';\n  }\n}\n\nint __android_log_write(int prio, const char *tag, const char *text) {\n  return fprintf(stderr, \"[%c/%.16s] %s\\n\", logTagChar(prio), tag, text);\n}\n\nint __android_log_print(int prio, const char *tag,  const char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n\n  int res = fprintf(stderr, \"[%c/%.16s] \", logTagChar(prio), tag);\n  res += vfprintf(stderr, \"%s\\n\", ap);\n\n  va_end(ap);\n  return res;\n}\n\n#endif\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/lyra/lyra.cpp",
    "content": "// Copyright 2004-present Facebook. All Rights Reserved.\n\n#include <fb/lyra.h>\n\n#include <ios>\n#include <memory>\n#include <vector>\n\n#include <dlfcn.h>\n#include <unwind.h>\n\nusing namespace std;\n\nnamespace facebook {\nnamespace lyra {\n\nnamespace {\n\nclass IosFlagsSaver {\n  ios_base& ios_;\n  ios_base::fmtflags flags_;\n\n public:\n  IosFlagsSaver(ios_base& ios)\n  : ios_(ios),\n    flags_(ios.flags())\n  {}\n\n  ~IosFlagsSaver() {\n    ios_.flags(flags_);\n  }\n};\n\nstruct BacktraceState {\n  size_t skip;\n  vector<InstructionPointer>& stackTrace;\n};\n\n_Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) {\n  BacktraceState* state = reinterpret_cast<BacktraceState*>(arg);\n  auto absoluteProgramCounter =\n      reinterpret_cast<InstructionPointer>(_Unwind_GetIP(context));\n\n  if (state->skip > 0) {\n    --state->skip;\n    return _URC_NO_REASON;\n  }\n\n  if (state->stackTrace.size() == state->stackTrace.capacity()) {\n    return _URC_END_OF_STACK;\n  }\n\n  state->stackTrace.push_back(absoluteProgramCounter);\n\n  return _URC_NO_REASON;\n}\n\nvoid captureBacktrace(size_t skip, vector<InstructionPointer>& stackTrace) {\n  // Beware of a bug on some platforms, which makes the trace loop until the\n  // buffer is full when it reaches a noexcept function. It seems to be fixed in\n  // newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846\n  // TODO(t10738439): Investigate workaround for the stack trace bug\n  BacktraceState state = {skip, stackTrace};\n  _Unwind_Backtrace(unwindCallback, &state);\n}\n}\n\nvoid getStackTrace(vector<InstructionPointer>& stackTrace, size_t skip) {\n  stackTrace.clear();\n  captureBacktrace(skip + 1, stackTrace);\n}\n\n// TODO(t10737622): Improve on-device symbolification\nvoid getStackTraceSymbols(vector<StackTraceElement>& symbols,\n                          const vector<InstructionPointer>& trace) {\n  symbols.clear();\n  symbols.reserve(trace.size());\n\n  for (size_t i = 0; i < trace.size(); ++i) {\n    Dl_info info;\n    if (dladdr(trace[i], &info)) {\n      symbols.emplace_back(trace[i], info.dli_fbase, info.dli_saddr,\n                           info.dli_fname ? info.dli_fname : \"\",\n                           info.dli_sname ? info.dli_sname : \"\");\n    }\n  }\n}\n\nostream& operator<<(ostream& out, const StackTraceElement& elm) {\n  IosFlagsSaver flags{out};\n\n  // TODO(t10748683): Add build id to the output\n  out << \"{dso=\" << elm.libraryName() << \" offset=\" << hex\n      << showbase << elm.libraryOffset();\n\n  if (!elm.functionName().empty()) {\n    out << \" func=\" << elm.functionName() << \"()+\" << elm.functionOffset();\n  }\n\n  out << \" build-id=\" << hex << setw(8) << 0\n      << \"}\";\n\n  return out;\n}\n\n// TODO(t10737667): The implement a tool that parse the stack trace and\n// symbolicate it\nostream& operator<<(ostream& out, const vector<StackTraceElement>& trace) {\n  IosFlagsSaver flags{out};\n\n  auto i = 0;\n  out << \"Backtrace:\\n\";\n  for (auto& elm : trace) {\n    out << \"    #\" << dec << setfill('0') << setw(2) << i++ << \" \" << elm << '\\n';\n  }\n\n  return out;\n}\n}\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/jni/fb/onload.cpp",
    "content": "/*\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <jni.h>\n#ifndef DISABLE_CPUCAP\n#include <fb/CpuCapabilities.h>\n#endif\n#include <fb/fbjni.h>\n\nusing namespace facebook::jni;\n\nvoid initialize_xplatinit();\nvoid initialize_fbjni();\n\nJNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {\n  return facebook::jni::initialize(vm, [] {\n    initialize_fbjni();\n#ifndef DISABLE_XPLAT\n    initialize_xplatinit();\n#endif\n#ifndef DISABLE_CPUCAP\n    initialize_cpucapabilities();\n#endif\n  });\n}\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/app_not_authorized.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n**\n** Copyright 2013, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\");\n** you may not use this file except in compliance with the License.\n** You may obtain a copy of the License at\n**\n**     http://www.apache.org/licenses/LICENSE-2.0\n**\n** Unless required by applicable law or agreed to in writing, software\n** distributed under the License is distributed on an \"AS IS\" BASIS,\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n** See the License for the specific language governing permissions and\n** limitations under the License.\n*/\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <!-- Customizable description text -->\n    <TextView android:id=\"@+id/description\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:paddingTop=\"16dip\"\n        android:paddingBottom=\"16dip\"\n        android:paddingStart=\"16dip\"\n        android:paddingEnd=\"16dip\"\n        android:text=\"Change not allowed\"\n    />\n\n    <!-- Horizontal divider line -->\n    <View android:layout_height=\"1dip\"\n        android:layout_width=\"match_parent\"\n        android:background=\"?android:attr/dividerHorizontal\" />\n\n    <!-- Alert dialog style buttons along the bottom. -->\n    <LinearLayout android:id=\"@+id/button_bar\"\n        style=\"?android:attr/buttonBarStyle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:measureWithLargestChild=\"true\">\n        <Button android:id=\"@android:id/button1\"\n            style=\"?android:attr/buttonBarButtonStyle\"\n            android:layout_width=\"0dp\" android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@android:string/yes\"\n            android:onClick=\"onCancelButtonClicked\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/choose_account_row.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:paddingLeft=\"16dp\"\n    android:paddingStart=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:paddingEnd=\"16dp\"\n    android:orientation=\"horizontal\" >\n\n   <ImageView android:id=\"@+id/account_row_icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"fill_parent\"\n        android:paddingRight=\"8dip\"\n        android:paddingEnd=\"8dip\" />\n\n    <TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:id=\"@+id/account_row_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n        android:gravity=\"center_vertical\"\n        android:minHeight=\"?android:listPreferredItemHeight\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/choose_account_type.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <View android:layout_height=\"3dip\"\n          android:layout_width=\"match_parent\"\n          android:background=\"#323232\"/>\n\n    <ListView android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1\"\n        android:drawSelectorOnTop=\"false\"\n        android:scrollbarAlwaysDrawVerticalTrack=\"true\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/choose_type_and_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <!-- Customizable description text -->\n    <TextView\n        android:id=\"@+id/description\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:paddingBottom=\"16dip\"\n        android:paddingEnd=\"16dip\"\n        android:paddingStart=\"16dip\"\n        android:paddingTop=\"16dip\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <!-- List of accounts, with \"Add new account\" as the last item -->\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:choiceMode=\"singleChoice\"\n        android:drawSelectorOnTop=\"false\"\n        android:scrollbarAlwaysDrawVerticalTrack=\"true\" />\n\n    <!-- Horizontal divider line -->\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dip\"\n        android:background=\"?android:attr/dividerHorizontal\" />\n\n    <!-- Alert dialog style buttons along the bottom. -->\n    <LinearLayout\n        android:id=\"@+id/button_bar\"\n        style=\"?android:attr/buttonBarStyle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:measureWithLargestChild=\"true\">\n\n        <Button\n            android:id=\"@android:id/button1\"\n            style=\"?android:attr/buttonBarButtonStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:onClick=\"onCancelButtonClicked\"\n            android:text=\"@android:string/no\" />\n\n        <Button\n            android:id=\"@android:id/button2\"\n            style=\"?android:attr/buttonBarButtonStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:onClick=\"onOkButtonClicked\"\n            android:text=\"@android:string/yes\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/custom_notification.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/im_main\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitXY\"/>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n        <LinearLayout\n            style=\"@style/notification_layout\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:id=\"@+id/btn_1\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_2\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_3\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_4\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_5\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_6\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_7\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_8\"\n                style=\"@style/notification_button\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            style=\"@style/notification_layout\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:id=\"@+id/btn_9\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_10\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_11\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_12\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_13\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_14\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_15\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_16\"\n                style=\"@style/notification_button\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            style=\"@style/notification_layout\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:id=\"@+id/btn_17\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_18\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_19\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_20\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_21\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_22\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_23\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_24\"\n                style=\"@style/notification_button\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            style=\"@style/notification_layout\"\n            android:orientation=\"horizontal\">\n\n            <ImageView\n                android:id=\"@+id/btn_25\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_26\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_27\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_28\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_29\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_30\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_31\"\n                style=\"@style/notification_button\"/>\n\n            <ImageView\n                android:id=\"@+id/btn_32\"\n                style=\"@style/notification_button\"/>\n\n        </LinearLayout>\n    </LinearLayout>\n</FrameLayout>"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/custom_notification_lite.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"match_parent\" >\n\n    <ImageView\n        android:id=\"@+id/im_main\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitXY\" />\n</FrameLayout>"
  },
  {
    "path": "VirtualApp/lib/src/main/res/layout/resolve_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<!--\r\n/* //device/apps/common/res/any/layout/resolve_list_item.xml\r\n**\r\n** Copyright 2006, The Android Open Source Project\r\n**\r\n** Licensed under the Apache License, Version 2.0 (the \"License\");\r\n** you may not use this file except in compliance with the License.\r\n** You may obtain a copy of the License at\r\n**\r\n**     http://www.apache.org/licenses/LICENSE-2.0\r\n**\r\n** Unless required by applicable law or agreed to in writing, software\r\n** distributed under the License is distributed on an \"AS IS\" BASIS,\r\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n** See the License for the specific language governing permissions and\r\n** limitations under the License.\r\n*/\r\n-->\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n              android:layout_width=\"match_parent\"\r\n              android:layout_height=\"wrap_content\"\r\n              android:orientation=\"horizontal\"\r\n              android:paddingBottom=\"4dp\"\r\n              android:paddingTop=\"4dp\">\r\n\r\n    <!-- Activity icon when presenting dialog\r\n         Size will be filled in by ResolverActivity -->\r\n    <ImageView\r\n        android:id=\"@+id/icon\"\r\n        android:layout_width=\"24dp\"\r\n        android:layout_height=\"24dp\"\r\n        android:layout_marginLeft=\"8dp\"\r\n        android:layout_gravity=\"start|center_vertical\"\r\n        android:layout_marginBottom=\"12dp\"\r\n        android:layout_marginTop=\"12dp\"\r\n        android:scaleType=\"fitCenter\"/>\r\n\r\n    <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n                  android:layout_width=\"wrap_content\"\r\n                  android:layout_height=\"wrap_content\"\r\n                  android:layout_marginLeft=\"8dp\"\r\n                  android:layout_gravity=\"start|center_vertical\"\r\n                  android:gravity=\"start|center_vertical\"\r\n                  android:orientation=\"vertical\">\r\n        <!-- Activity name -->\r\n        <TextView\r\n            android:id=\"@+id/text1\"\r\n            android:layout_width=\"wrap_content\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:ellipsize=\"marquee\"\r\n            android:maxLines=\"1\"\r\n            android:minLines=\"1\"/>\r\n        <!-- Extended activity info to distinguish between duplicate activity names -->\r\n        <TextView\r\n            android:id=\"@+id/text2\"\r\n            android:layout_width=\"wrap_content\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:ellipsize=\"marquee\"\r\n            android:maxLines=\"1\"\r\n            android:minLines=\"1\"\r\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\r\n    </LinearLayout>\r\n</LinearLayout>\r\n\r\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- notification -->\n    <dimen name=\"match_parent\">-1px</dimen>\n    <dimen name=\"standard_notification_panel_width\">416dp\n    </dimen><!-- includes notification_side_padding on each side -->\n    <!-- Height of a small notification in the status bar -->\n    <dimen name=\"notification_min_height\">64dp</dimen>\n    <dimen name=\"notification_side_padding\">8dp</dimen>\n    <dimen name=\"notification_panel_width\">-1dp</dimen>\n    <!-- Height of a large notification in the status bar -->\n    <dimen name=\"notification_max_height\">256dp</dimen>\n    <dimen name=\"notification_padding\">4dp</dimen>\n    <!-- Height of a medium notification in the status bar -->\n    <dimen name=\"notification_mid_height\">128dp</dimen>\n</resources>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values/integer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<resources>\r\n    <integer name=\"config_maxResolverActivityColumns\">8</integer>\r\n</resources>"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"engine_process_name\">:x</string>\n    <string name=\"virtual_installer\">VirtualPackage Installer</string>\n    <string name=\"owner_name\">Admin</string>\n    <string name=\"choose\">Choose</string>\n    <string name=\"choose_empty\">Chooser is Empty</string>\n    <string name=\"noApplications\">No find applications</string>\n    <string name=\"add_account_button_label\">Add account</string>\n    <string name=\"create_shortcut_already_exist\">The shortcut already exists</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values/styles.xml",
    "content": "<resources>\n    <style name=\"notification_layout\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">0dp</item>\n        <item name=\"android:layout_weight\">1</item>\n    </style>\n    <style name=\"notification_button\">\n        <item name=\"android:layout_width\">0dp</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:layout_weight\">1</item>\n    </style>\n\n    <style name=\"VATheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowDisablePreview\">true</item>\n    </style>\n    <style name=\"VAAlertTheme\" parent=\"android:Theme.DeviceDefault.Dialog\">\n    </style>\n</resources>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string name=\"virtual_installer\">Установщик VirtualPackage</string>\n\t<string name=\"owner_name\">Админ</string>\n\t<string name=\"choose\">Выбрать</string>\n\t<string name=\"choose_empty\">Выбор пуст</string>\n\t<string name=\"noApplications\">Нет приложений для поиска</string>\n\t<string name=\"add_account_button_label\">Добавить аккаунт</string>\n\t<string name=\"create_shortcut_already_exist\">Этот ярлык уже существует</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/lib/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string name=\"virtual_installer\">Встановлювач VirtualPackage</string>\n\t<string name=\"owner_name\">Адмін</string>\n\t<string name=\"choose\">Вибрати</string>\n\t<string name=\"choose_empty\">Пустий вибір</string>\n\t<string name=\"noApplications\">Немає додатків для пошуку</string>\n\t<string name=\"add_account_button_label\">Додати акаунт</string>\n\t<string name=\"create_shortcut_already_exist\">Цей ярлик вже існує</string>\n</resources>\n"
  },
  {
    "path": "VirtualApp/settings.gradle",
    "content": "include ':lib', ':app', ':launcher'\nrootProject.name=\"VirtualXposed\"\n"
  }
]