├── .gitignore ├── LICENSE ├── README.md ├── aosp build.md ├── art └── runtime │ ├── Android.mk │ ├── art_method.cc │ ├── art_method.h │ ├── aupk.cc │ ├── aupk.h │ ├── interpreter │ ├── interpreter.cc │ └── interpreter_switch_impl.cc │ ├── json.hpp │ ├── native │ └── aupk_method.cc │ └── runtime.cc ├── frameworks └── base │ └── core │ └── java │ └── android │ └── app │ ├── ActivityThread.java │ └── Aupk.java └── img ├── Snipaste_2021-03-28_19-56-55.png ├── Snipaste_2021-03-28_19-57-20.png ├── Snipaste_2021-03-28_22-43-16.png ├── Snipaste_2021-03-28_22-54-27.png ├── Snipaste_2021-03-28_23-08-22.png ├── Snipaste_2021-03-28_23-09-38.png └── Snipaste_2021-03-28_23-13-32.png /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | main.js 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Harrison 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AUPK 2 | 3 | Android Art虚拟机下的主动调用脱壳方案。 4 | 5 | 该版本在`android 7.1.1_r1`上进行实现,并为Nexuse 5X做了适配(驱动代号NMF26F)。 6 | 7 | 若需要适配其他版本,请自行移植。 8 | 9 | 关于AOSP编译,可以参考我的笔记`aosp build.md`; 10 | 11 | 关于AUPK的原理和流程,请移步看雪: 12 | 13 | [AUPK:基于Art虚拟机的脱壳机](https://bbs.pediy.com/thread-266716.htm) 14 | 15 | ###### 下载: 16 | 17 | 百度网盘 18 | 19 | 链接:https://pan.baidu.com/s/1Rj2Un2ox9u08K4p1rPx0Kw 20 | 提取码:aupk 21 | 22 | or 23 | 24 | realeases:https://github.com/FeJQ/AUPK/releases 25 | 26 | 27 | 28 | ###### 使用方法: 29 | 30 | 1. 下载镜像,并运行flash.bat刷机 31 | 32 | 2. 安装,并运行待脱壳的app 33 | 34 | 3. 获取app的包名,并写入配置文件: 35 | 36 | ```shell 37 | $ echo "your.app.package">data/local/tmp/aupk.config" 38 | ``` 39 | 40 | 4. 等待脱壳结束,直到logcat 打印出`Aupk run over`。 41 | 42 | 5. 使用[DexPatcher](https://github.com/FeJQ/DexPatcher)对Dex文件进行修复 43 | 44 | 45 | 46 | ###### 示例: 47 | 48 | 首先安装目标app 49 | 50 | ```shell 51 | $ adb install your_app 52 | ``` 53 | 54 | 运行app,可在logcat看到如下信息: 55 | 56 | ![Snipaste_2021-03-28_19-57-20](img/Snipaste_2021-03-28_19-57-20.png) 57 | 58 | 此时`data/data/your_app/aupk`下多出许多文件 59 | 60 | ```shell 61 | $ cd data/data/your_app/aupk 62 | $ ls -l 63 | ``` 64 | 65 | ![Snipaste_2021-03-28_19-56-55](img/Snipaste_2021-03-28_19-56-55.png) 66 | 67 | 其中,`.dex`为整体dump下来的Dex文件,`class.json`记录了Dex文件里所有的类名,前缀数字代表Dex文件的大小。 68 | 69 | 可以用`findstr`命令来查找某一个类的类名在哪个文件中,如: 70 | 71 | ```shell 72 | $ findstr /m "SplashActivity" *class.json 73 | ``` 74 | 75 | ![Snipaste_2021-03-28_22-43-16](img/Snipaste_2021-03-28_22-43-16.png) 76 | 77 | 78 | 79 | 可以看到,"SplashActivity"类在8273364大小的Dex文件中,那么,我们可以通过以下命令,来写入配置文件 80 | 81 | 以开始对`8273364_ExecuteSwitchImpl_class.json`里所有的类的所有方法进行主动调用 82 | 83 | ```shell 84 | $ echo "com.klcxkj.zqxy 8273364_ExecuteSwitchImpl_class.json">data/local/tmp/aupk.config 85 | ``` 86 | 87 | 或者对所有的Dex里的类的所有方法进行主动调用: 88 | 89 | ```shell 90 | $ echo "com.klcxkj.zqxy">data/local/tmp/aupk.config 91 | ``` 92 | 93 | 主动调用过程中打印的log: 94 | 95 | ![Snipaste_2021-03-28_22-54-27](img/Snipaste_2021-03-28_22-54-27.png) 96 | 97 | 有的壳hook了Log函数,导致Log.i()打印不出来消息,但jni层的LOG和Log.e()依然有效,当打印出`Aupk run over`时,代表整个主动调用过程结束,可以在`data/data/you_app/aupk`下看到一些以`method.json`结尾的文件,这些文件包含了Dex文件的函数CodeItem信息,用于后面对Dex文件的修复。 98 | 99 | 并非等整个主动调用过程结束才会生成`method.json`文件,而是每完成对一个`class.json`文件的解析和调用,就会立即生成对应的`method.json`,所以,利用主动调用的这段时间,你可以先修复已经完成了主动调用的Dex文件,或者去泡杯咖啡。 100 | 101 | 将脱下来的文件拷贝到电脑: 102 | 103 | ```shell 104 | $ adb pull data/data/your_app/aupk 105 | ``` 106 | 107 | 开始修复Dex,回填CodeItem: 108 | 109 | ```shell 110 | $ dp fix -d 8273364_ExecuteSwitchImpl.dex -j 8273364_ExecuteSwitchImpl_method.json --nolog 111 | ``` 112 | 113 | 等待片刻,即可完成修复: 114 | 115 | ![Snipaste_2021-03-28_23-08-22](img/Snipaste_2021-03-28_23-08-22.png) 116 | 117 | 带patched后缀的就是修复后的Dex文件 118 | 119 | ![Snipaste_2021-03-28_23-09-38](img/Snipaste_2021-03-28_23-09-38.png) 120 | 121 | 反编译看看效果: 122 | 123 | ![Snipaste_2021-03-28_23-13-32](img/Snipaste_2021-03-28_23-13-32.png) -------------------------------------------------------------------------------- /aosp build.md: -------------------------------------------------------------------------------- 1 | ## 编译AOSP 2 | 3 | 4 | 5 | 6 | 7 | ### 环境搭建 8 | 9 | 参考文献 10 | 11 | > [source.android.com:为AOSP搭建构建环境](https://source.android.com/source/initializing) 12 | 13 | 1. ##### 准备系统 14 | 15 | 下载并安装`Ubuntu 16.4 LTS` 16 | 17 | 2. ##### 更换国内镜像源(可选) 18 | 19 | 打开`software & updates`,选择最佳镜像源,随后`close`->`reload`->`install`->`reboot`. 20 | 21 | 3. ##### 更新软件 22 | 23 | ```shell 24 | $ sudo apt-get update 25 | ``` 26 | 27 | 4. ##### 安装`openjdk` 28 | ```shell 29 | $ sudo apt-get install openjdk-8-jdk 30 | ``` 31 | 32 | `JDK`支持的版本: 33 | 34 | > Android **7.0** (Nougat) – Android **8.0** (Oreo): 35 | > Ubuntu:OpenJDK **8** 36 | > Mac OS X:JDK 8u45 或更高版本 37 | 38 | > Android **5.x **(Lollipop) – Android **6.0** (Marshmallow): 39 | > Ubuntu:OpenJDK **7** 40 | > Mac OS X:jdk-7u71-macosx-x64.dmg 41 | 42 | > Android **2.3.x** (Gingerbread) – Android **4.4.x** (KitKat): 43 | > Ubuntu:Java JDK **6** 44 | > Mac OS X:Java JDK 6 45 | 46 | > Android **1.5** (Cupcake) – Android **2.2.x** (Froyo): 47 | > Ubuntu:Java JDK **5** 48 | 49 | 50 | 51 | 5. ##### 安装依赖包 52 | 53 | ```shell 54 | $ sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig 55 | ``` 56 | 57 | 6. ##### 如需使用 SELinux 工具进行策略分析,您还需要安装 `python-networkx` 软件包 58 | 59 | ```shell 60 | $ sudo apt-get install python-networkx 61 | ``` 62 | 63 | 7. ##### 如果您使用的是 LDAP 并且希望运行 ART 主机测试,还需要安装 `libnss-sss:i386` 软件包。 64 | 65 | ```shell 66 | $ sudo apt-get install libnss-sss:i386 67 | ``` 68 | 69 | 8. ##### 开启缓存(可选) 70 | 71 | 1. 安装`ccache` 72 | 73 | ```shell 74 | $ sudo apt-get install ccache 75 | ``` 76 | 77 | 2. 在`home`主目录的`.bashrc`中加入: 78 | 79 | ``` 80 | export USE_CCACHE=1 81 | ``` 82 | 83 | 3. 指定缓存目录,也需要在`.bashrc`中加入,默认为当前用户目录下的.ccache 84 | 85 | ``` 86 | export CCACHE_DIR=/home/fejq/.ccache 87 | ``` 88 | 89 | 4. 在修改了~/.bashrc 后记得source 下,或者直接重启虚拟机,不然刚刚添加的变量不会生效。 90 | 91 | ```shell 92 | $ source ~/.bashrc 93 | ``` 94 | 95 | 5. 配置缓存最大小,这个参数保存在`CCACHE_DIR`所在的目录 96 | 97 | ```shell 98 | # 配置缓存最大小 99 | $ ccache -M 100G 100 | ``` 101 | 102 | 6. 查看缓存状态 103 | 104 | ```shell 105 | $ ccache -s 106 | ``` 107 | 108 | ### 下载源码 109 | 110 | 参考文献 111 | 112 | >[source.android.com:下载源码](https://source.android.com/source/downloading) 113 | > 114 | >[清华大学开源软件镜像站:Android 镜像使用帮助](https://mirrors.tuna.tsinghua.edu.cn/) 115 | 116 | 1. ##### 安装`Repo` 117 | 118 | 1. 确保主目录`/home`下有一个 bin/ 目录,并且该目录包含在路径中 119 | 120 | ```shell 121 | $ mkdir ~/bin 122 | # 添加bin目录到环境变量 123 | $ PATH=~/bin:$PATH 124 | # 打印环境变量 125 | $ echo $PATH 126 | ``` 127 | 128 | 2. 下载 `Repo` 工具,并确保它可执行 129 | 130 | ```shell 131 | curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo 132 | chmod a+x ~/bin/repo 133 | ``` 134 | 135 | > 可能需要更改DNS: 136 | > 137 | > ```shell 138 | > sudo gedit /etc/network/interfaces 139 | > ``` 140 | > 141 | > 在末尾追加: 142 | > 143 | > ``` 144 | > dns-nameservers 8.8.8.8 145 | > ``` 146 | 147 | 3. ##### 初始化仓库 148 | 149 | 初始化仓库: 150 | 151 | ```shell 152 | repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest 153 | ``` 154 | 155 | **如果提示无法连接到 gerrit.googlesource.com,请参照[git-repo的帮助页面](https://mirrors.tuna.tsinghua.edu.cn/help/git-repo)的更新一节。** 156 | 157 | 如果需要某个特定的 Android 版本([列表](https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds)): 158 | 159 | ```shell 160 | repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-8.0.0_r35 161 | ``` 162 | 163 | 4. ##### 同步源码树 164 | 165 | ```shell 166 | repo sync 167 | ``` 168 | 169 | 170 | 171 | > 同步过程受网络状况影响,在同步过程中可能会出现错误,卡住不动等现象,此时,皆可由手动重新执行`repo sync`命令来解决,亦可通过以下脚本来自动执行 172 | > 173 | > 174 | > 175 | > 新建脚本`repo-sync.sh` 176 | > 177 | > 178 | > 179 | > **当出现错误而导致同步停止时,重新开始同步** 180 | > 181 | > ```shell 182 | > #!/bin/bash 183 | > echo "======= start repo sync =======" 184 | > # 进入同步目录(之前执行了repo init的目录) 185 | > cd ~/AOSP/android-8.0.0_r35 186 | > repo sync -j4 187 | > while [ $? == 1 ]; do 188 | > echo "====== sync failed! re-sync again =====" 189 | > sleep 3 190 | > repo sync -j4 191 | > ``` 192 | > 193 | > **当同步卡住不动时,重新开始同步** 194 | > 195 | > 安装网络监测工具`ifstat` 196 | > 197 | > ```shell 198 | > sudo apt-get install ifstat 199 | > ``` 200 | > 201 | > 运行脚本 202 | > 203 | > ```shell 204 | > #!/bin/bash 205 | > 206 | > #杀掉repo sync进程 207 | > kill_reposync() { 208 | > PID=`ps aux |grep python|grep [r]epo |awk '{print $2}'` 209 | > [[ -n $PID ]] && kill $PID 210 | > } 211 | > 212 | > #启动reposync进程 213 | > start_reposync() { 214 | > repo sync & 215 | > } 216 | > 217 | > #重启reposync进程 218 | > restart_sync() { 219 | > kill_reposync 220 | > start_reposync 221 | > } 222 | > 223 | > #网络检测相关阈值 224 | > th_net_value="30" #实际检测,repo sync卡住时,网卡入口数据小于10 225 | > th_retry_times=100 #低于网络检测阈值次数限制 226 | > ((count_low=0)) 227 | > 228 | > restart_sync 229 | > 230 | > 231 | > while [[ 1 ]]; do 232 | > # 用ifstat检测网速 233 | > cur_speed=`ifstat 1 1 | tail -n 1 | awk '{print $1}'` 234 | > 235 | > result=$(echo "$cur_speed < $th_net_value" | bc) 236 | > if [[ $result == "1" ]]; then 237 | > ((count_low++)) 238 | > else 239 | > ((count_low=0)) 240 | > fi 241 | > if ((count_low > th_retry_times)); then 242 | > ((count_low=0)) 243 | > echo "restart repo sync" 244 | > restart_sync 245 | > fi 246 | > done 247 | > ``` 248 | > 249 | > 250 | > 251 | > 参考: 252 | > 253 | > [关于使用repo时repo init和repo sync失败的一个解决方案](https://www.cnblogs.com/daimadebanyungong/p/7765218.html) 254 | 255 | > 需保证下载的源码,有对应的驱动支持 256 | > 257 | > [源代码标记](https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds) 258 | > 259 | > [驱动支持](https://developers.google.cn/android/drivers) 260 | > 261 | > 如: 262 | > 263 | > `Nexus 5X`有对 `Android 7.1.1`的驱动支持,代号为`NMF26F`: 264 | > 265 | > > Nexus 5X binaries for Android 7.1.1 (NMF26F) 266 | > 267 | > 搜索`build`号为`NMF26F`的源码版本,可以找到`android-7.1.1_r1`,即该版本的源码有对`Nexus 5X`的支持 268 | 269 | 270 | ### 开始编译 271 | 272 | 1. ##### 清理 273 | 274 | ```shell 275 | $ make clobber 276 | ``` 277 | 278 | 2. ##### 设置环境 279 | 280 | ```shell 281 | $ source build/envsetup.sh 282 | ``` 283 | 284 | 3. ##### 选择目标 285 | 286 | ```shell 287 | $ lunch 288 | ``` 289 | 290 | ```shell 291 | $ lunch product_name-build_variant 292 | # eg:lunch aosp_bullhead-eng 293 | ``` 294 | 295 | 4. ##### 开始编译 296 | 297 | ```shell 298 | $ time make -j4 299 | ``` 300 | 301 | 302 | -------------------------------------------------------------------------------- /art/runtime/Android.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 The Android Open Source Project 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | LOCAL_PATH := $(call my-dir) 18 | 19 | include art/build/Android.common_build.mk 20 | 21 | LIBART_COMMON_SRC_FILES := \ 22 | aupk.cc \ 23 | json.hpp \ 24 | art_field.cc \ 25 | art_method.cc \ 26 | atomic.cc.arm \ 27 | barrier.cc \ 28 | base/allocator.cc \ 29 | base/arena_allocator.cc \ 30 | base/arena_bit_vector.cc \ 31 | base/bit_vector.cc \ 32 | base/file_magic.cc \ 33 | base/hex_dump.cc \ 34 | base/logging.cc \ 35 | base/mutex.cc \ 36 | base/scoped_arena_allocator.cc \ 37 | base/scoped_flock.cc \ 38 | base/stringpiece.cc \ 39 | base/stringprintf.cc \ 40 | base/time_utils.cc \ 41 | base/timing_logger.cc \ 42 | base/unix_file/fd_file.cc \ 43 | base/unix_file/random_access_file_utils.cc \ 44 | check_jni.cc \ 45 | class_linker.cc \ 46 | class_table.cc \ 47 | code_simulator_container.cc \ 48 | common_throws.cc \ 49 | compiler_filter.cc \ 50 | debugger.cc \ 51 | dex_file.cc \ 52 | dex_file_verifier.cc \ 53 | dex_instruction.cc \ 54 | elf_file.cc \ 55 | fault_handler.cc \ 56 | gc/allocation_record.cc \ 57 | gc/allocator/dlmalloc.cc \ 58 | gc/allocator/rosalloc.cc \ 59 | gc/accounting/bitmap.cc \ 60 | gc/accounting/card_table.cc \ 61 | gc/accounting/heap_bitmap.cc \ 62 | gc/accounting/mod_union_table.cc \ 63 | gc/accounting/remembered_set.cc \ 64 | gc/accounting/space_bitmap.cc \ 65 | gc/collector/concurrent_copying.cc \ 66 | gc/collector/garbage_collector.cc \ 67 | gc/collector/immune_region.cc \ 68 | gc/collector/immune_spaces.cc \ 69 | gc/collector/mark_compact.cc \ 70 | gc/collector/mark_sweep.cc \ 71 | gc/collector/partial_mark_sweep.cc \ 72 | gc/collector/semi_space.cc \ 73 | gc/collector/sticky_mark_sweep.cc \ 74 | gc/gc_cause.cc \ 75 | gc/heap.cc \ 76 | gc/reference_processor.cc \ 77 | gc/reference_queue.cc \ 78 | gc/scoped_gc_critical_section.cc \ 79 | gc/space/bump_pointer_space.cc \ 80 | gc/space/dlmalloc_space.cc \ 81 | gc/space/image_space.cc \ 82 | gc/space/large_object_space.cc \ 83 | gc/space/malloc_space.cc \ 84 | gc/space/region_space.cc \ 85 | gc/space/rosalloc_space.cc \ 86 | gc/space/space.cc \ 87 | gc/space/zygote_space.cc \ 88 | gc/task_processor.cc \ 89 | hprof/hprof.cc \ 90 | image.cc \ 91 | indirect_reference_table.cc \ 92 | instrumentation.cc \ 93 | intern_table.cc \ 94 | interpreter/interpreter.cc \ 95 | interpreter/interpreter_common.cc \ 96 | interpreter/interpreter_goto_table_impl.cc \ 97 | interpreter/interpreter_switch_impl.cc \ 98 | interpreter/unstarted_runtime.cc \ 99 | java_vm_ext.cc \ 100 | jdwp/jdwp_event.cc \ 101 | jdwp/jdwp_expand_buf.cc \ 102 | jdwp/jdwp_handler.cc \ 103 | jdwp/jdwp_main.cc \ 104 | jdwp/jdwp_request.cc \ 105 | jdwp/jdwp_socket.cc \ 106 | jdwp/object_registry.cc \ 107 | jni_env_ext.cc \ 108 | jit/debugger_interface.cc \ 109 | jit/jit.cc \ 110 | jit/jit_code_cache.cc \ 111 | jit/offline_profiling_info.cc \ 112 | jit/profiling_info.cc \ 113 | jit/profile_saver.cc \ 114 | lambda/art_lambda_method.cc \ 115 | lambda/box_table.cc \ 116 | lambda/closure.cc \ 117 | lambda/closure_builder.cc \ 118 | lambda/leaking_allocator.cc \ 119 | jni_internal.cc \ 120 | jobject_comparator.cc \ 121 | linear_alloc.cc \ 122 | mem_map.cc \ 123 | memory_region.cc \ 124 | mirror/abstract_method.cc \ 125 | mirror/array.cc \ 126 | mirror/class.cc \ 127 | mirror/dex_cache.cc \ 128 | mirror/field.cc \ 129 | mirror/method.cc \ 130 | mirror/object.cc \ 131 | mirror/reference.cc \ 132 | mirror/stack_trace_element.cc \ 133 | mirror/string.cc \ 134 | mirror/throwable.cc \ 135 | monitor.cc \ 136 | native_bridge_art_interface.cc \ 137 | native/aupk_method.cc \ 138 | native/dalvik_system_DexFile.cc \ 139 | native/dalvik_system_VMDebug.cc \ 140 | native/dalvik_system_VMRuntime.cc \ 141 | native/dalvik_system_VMStack.cc \ 142 | native/dalvik_system_ZygoteHooks.cc \ 143 | native/java_lang_Class.cc \ 144 | native/java_lang_DexCache.cc \ 145 | native/java_lang_Object.cc \ 146 | native/java_lang_String.cc \ 147 | native/java_lang_StringFactory.cc \ 148 | native/java_lang_System.cc \ 149 | native/java_lang_Thread.cc \ 150 | native/java_lang_Throwable.cc \ 151 | native/java_lang_VMClassLoader.cc \ 152 | native/java_lang_ref_FinalizerReference.cc \ 153 | native/java_lang_ref_Reference.cc \ 154 | native/java_lang_reflect_AbstractMethod.cc \ 155 | native/java_lang_reflect_Array.cc \ 156 | native/java_lang_reflect_Constructor.cc \ 157 | native/java_lang_reflect_Field.cc \ 158 | native/java_lang_reflect_Method.cc \ 159 | native/java_lang_reflect_Proxy.cc \ 160 | native/java_util_concurrent_atomic_AtomicLong.cc \ 161 | native/libcore_util_CharsetUtils.cc \ 162 | native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \ 163 | native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \ 164 | native/sun_misc_Unsafe.cc \ 165 | oat.cc \ 166 | oat_file.cc \ 167 | oat_file_assistant.cc \ 168 | oat_file_manager.cc \ 169 | oat_quick_method_header.cc \ 170 | object_lock.cc \ 171 | offsets.cc \ 172 | os_linux.cc \ 173 | parsed_options.cc \ 174 | primitive.cc \ 175 | profiler.cc \ 176 | quick_exception_handler.cc \ 177 | quick/inline_method_analyser.cc \ 178 | reference_table.cc \ 179 | reflection.cc \ 180 | runtime.cc \ 181 | runtime_options.cc \ 182 | signal_catcher.cc \ 183 | stack.cc \ 184 | stack_map.cc \ 185 | thread.cc \ 186 | thread_list.cc \ 187 | thread_pool.cc \ 188 | trace.cc \ 189 | transaction.cc \ 190 | type_lookup_table.cc \ 191 | utf.cc \ 192 | utils.cc \ 193 | verifier/instruction_flags.cc \ 194 | verifier/method_verifier.cc \ 195 | verifier/reg_type.cc \ 196 | verifier/reg_type_cache.cc \ 197 | verifier/register_line.cc \ 198 | well_known_classes.cc \ 199 | zip_archive.cc 200 | 201 | LIBART_COMMON_SRC_FILES += \ 202 | arch/context.cc \ 203 | arch/instruction_set.cc \ 204 | arch/instruction_set_features.cc \ 205 | arch/memcmp16.cc \ 206 | arch/arm/instruction_set_features_arm.cc \ 207 | arch/arm/registers_arm.cc \ 208 | arch/arm64/instruction_set_features_arm64.cc \ 209 | arch/arm64/registers_arm64.cc \ 210 | arch/mips/instruction_set_features_mips.cc \ 211 | arch/mips/registers_mips.cc \ 212 | arch/mips64/instruction_set_features_mips64.cc \ 213 | arch/mips64/registers_mips64.cc \ 214 | arch/x86/instruction_set_features_x86.cc \ 215 | arch/x86/registers_x86.cc \ 216 | arch/x86_64/registers_x86_64.cc \ 217 | entrypoints/entrypoint_utils.cc \ 218 | entrypoints/jni/jni_entrypoints.cc \ 219 | entrypoints/math_entrypoints.cc \ 220 | entrypoints/quick/quick_alloc_entrypoints.cc \ 221 | entrypoints/quick/quick_cast_entrypoints.cc \ 222 | entrypoints/quick/quick_deoptimization_entrypoints.cc \ 223 | entrypoints/quick/quick_dexcache_entrypoints.cc \ 224 | entrypoints/quick/quick_field_entrypoints.cc \ 225 | entrypoints/quick/quick_fillarray_entrypoints.cc \ 226 | entrypoints/quick/quick_instrumentation_entrypoints.cc \ 227 | entrypoints/quick/quick_jni_entrypoints.cc \ 228 | entrypoints/quick/quick_lock_entrypoints.cc \ 229 | entrypoints/quick/quick_math_entrypoints.cc \ 230 | entrypoints/quick/quick_thread_entrypoints.cc \ 231 | entrypoints/quick/quick_throw_entrypoints.cc \ 232 | entrypoints/quick/quick_trampoline_entrypoints.cc 233 | 234 | LIBART_TARGET_LDFLAGS := 235 | LIBART_HOST_LDFLAGS := 236 | 237 | # Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where 238 | # we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when 239 | # new jit code is generated. We don't want it to be called when a different function with the same 240 | # (empty) body is called. 241 | JIT_DEBUG_REGISTER_CODE_LDFLAGS := -Wl,--keep-unique,__jit_debug_register_code 242 | LIBART_TARGET_LDFLAGS_arm := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS) 243 | LIBART_TARGET_LDFLAGS_arm64 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS) 244 | LIBART_TARGET_LDFLAGS_x86 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS) 245 | LIBART_TARGET_LDFLAGS_x86_64 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS) 246 | JIT_DEBUG_REGISTER_CODE_LDFLAGS := 247 | 248 | LIBART_TARGET_SRC_FILES := \ 249 | $(LIBART_COMMON_SRC_FILES) \ 250 | jdwp/jdwp_adb.cc \ 251 | monitor_android.cc \ 252 | runtime_android.cc \ 253 | thread_android.cc 254 | 255 | LIBART_TARGET_SRC_FILES_arm := \ 256 | interpreter/mterp/mterp.cc \ 257 | interpreter/mterp/out/mterp_arm.S \ 258 | arch/arm/context_arm.cc.arm \ 259 | arch/arm/entrypoints_init_arm.cc \ 260 | arch/arm/instruction_set_features_assembly_tests.S \ 261 | arch/arm/jni_entrypoints_arm.S \ 262 | arch/arm/memcmp16_arm.S \ 263 | arch/arm/quick_entrypoints_arm.S \ 264 | arch/arm/quick_entrypoints_cc_arm.cc \ 265 | arch/arm/thread_arm.cc \ 266 | arch/arm/fault_handler_arm.cc 267 | 268 | LIBART_TARGET_SRC_FILES_arm64 := \ 269 | interpreter/mterp/mterp.cc \ 270 | interpreter/mterp/out/mterp_arm64.S \ 271 | arch/arm64/context_arm64.cc \ 272 | arch/arm64/entrypoints_init_arm64.cc \ 273 | arch/arm64/jni_entrypoints_arm64.S \ 274 | arch/arm64/memcmp16_arm64.S \ 275 | arch/arm64/quick_entrypoints_arm64.S \ 276 | arch/arm64/thread_arm64.cc \ 277 | monitor_pool.cc \ 278 | arch/arm64/fault_handler_arm64.cc 279 | 280 | LIBART_SRC_FILES_x86 := \ 281 | interpreter/mterp/mterp.cc \ 282 | interpreter/mterp/out/mterp_x86.S \ 283 | arch/x86/context_x86.cc \ 284 | arch/x86/entrypoints_init_x86.cc \ 285 | arch/x86/jni_entrypoints_x86.S \ 286 | arch/x86/memcmp16_x86.S \ 287 | arch/x86/quick_entrypoints_x86.S \ 288 | arch/x86/thread_x86.cc \ 289 | arch/x86/fault_handler_x86.cc 290 | 291 | LIBART_TARGET_SRC_FILES_x86 := \ 292 | $(LIBART_SRC_FILES_x86) 293 | 294 | # Note that the fault_handler_x86.cc is not a mistake. This file is 295 | # shared between the x86 and x86_64 architectures. 296 | LIBART_SRC_FILES_x86_64 := \ 297 | interpreter/mterp/mterp.cc \ 298 | interpreter/mterp/out/mterp_x86_64.S \ 299 | arch/x86_64/context_x86_64.cc \ 300 | arch/x86_64/entrypoints_init_x86_64.cc \ 301 | arch/x86_64/jni_entrypoints_x86_64.S \ 302 | arch/x86_64/memcmp16_x86_64.S \ 303 | arch/x86_64/quick_entrypoints_x86_64.S \ 304 | arch/x86_64/thread_x86_64.cc \ 305 | monitor_pool.cc \ 306 | arch/x86/fault_handler_x86.cc 307 | 308 | LIBART_TARGET_SRC_FILES_x86_64 := \ 309 | $(LIBART_SRC_FILES_x86_64) \ 310 | 311 | LIBART_TARGET_SRC_FILES_mips := \ 312 | interpreter/mterp/mterp.cc \ 313 | interpreter/mterp/out/mterp_mips.S \ 314 | arch/mips/context_mips.cc \ 315 | arch/mips/entrypoints_init_mips.cc \ 316 | arch/mips/jni_entrypoints_mips.S \ 317 | arch/mips/memcmp16_mips.S \ 318 | arch/mips/quick_entrypoints_mips.S \ 319 | arch/mips/thread_mips.cc \ 320 | arch/mips/fault_handler_mips.cc 321 | 322 | LIBART_TARGET_SRC_FILES_mips64 := \ 323 | interpreter/mterp/mterp.cc \ 324 | interpreter/mterp/out/mterp_mips64.S \ 325 | arch/mips64/context_mips64.cc \ 326 | arch/mips64/entrypoints_init_mips64.cc \ 327 | arch/mips64/jni_entrypoints_mips64.S \ 328 | arch/mips64/memcmp16_mips64.S \ 329 | arch/mips64/quick_entrypoints_mips64.S \ 330 | arch/mips64/thread_mips64.cc \ 331 | monitor_pool.cc \ 332 | arch/mips64/fault_handler_mips64.cc 333 | 334 | LIBART_HOST_SRC_FILES := \ 335 | $(LIBART_COMMON_SRC_FILES) \ 336 | monitor_linux.cc \ 337 | runtime_linux.cc \ 338 | thread_linux.cc 339 | 340 | LIBART_HOST_SRC_FILES_32 := \ 341 | $(LIBART_SRC_FILES_x86) 342 | 343 | LIBART_HOST_SRC_FILES_64 := \ 344 | $(LIBART_SRC_FILES_x86_64) 345 | 346 | LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \ 347 | arch/instruction_set.h \ 348 | base/allocator.h \ 349 | base/mutex.h \ 350 | debugger.h \ 351 | base/unix_file/fd_file.h \ 352 | dex_file.h \ 353 | dex_instruction.h \ 354 | dex_instruction_utils.h \ 355 | gc_root.h \ 356 | gc/allocator_type.h \ 357 | gc/allocator/rosalloc.h \ 358 | gc/collector_type.h \ 359 | gc/collector/gc_type.h \ 360 | gc/heap.h \ 361 | gc/space/region_space.h \ 362 | gc/space/space.h \ 363 | gc/weak_root_state.h \ 364 | image.h \ 365 | instrumentation.h \ 366 | indirect_reference_table.h \ 367 | invoke_type.h \ 368 | jdwp/jdwp.h \ 369 | jdwp/jdwp_constants.h \ 370 | lock_word.h \ 371 | mirror/class.h \ 372 | oat.h \ 373 | object_callbacks.h \ 374 | process_state.h \ 375 | profiler_options.h \ 376 | quick/inline_method_analyser.h \ 377 | runtime.h \ 378 | stack.h \ 379 | thread.h \ 380 | thread_state.h \ 381 | verifier/method_verifier.h 382 | 383 | LIBOPENJDKJVM_SRC_FILES := openjdkjvm/OpenjdkJvm.cc 384 | 385 | LIBART_CFLAGS := -DBUILDING_LIBART=1 386 | 387 | LIBART_TARGET_CFLAGS := 388 | LIBART_HOST_CFLAGS := 389 | 390 | # Default dex2oat instruction set features. 391 | LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES := default 392 | LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default 393 | 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default 394 | ifeq ($(DEX2OAT_TARGET_ARCH),arm) 395 | ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver)) 396 | LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := atomic_ldrd_strd,div 397 | else 398 | ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7)) 399 | LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div 400 | endif 401 | endif 402 | endif 403 | ifeq ($(2ND_DEX2OAT_TARGET_ARCH),arm) 404 | ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver)) 405 | 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := atomic_ldrd_strd,div 406 | else 407 | ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7)) 408 | 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div 409 | endif 410 | endif 411 | endif 412 | 413 | # $(1): target or host 414 | # $(2): ndebug or debug 415 | # $(3): static or shared (note that static only applies for host) 416 | # $(4): module name : either libart or libopenjdkjvm 417 | define build-runtime-library 418 | ifneq ($(1),target) 419 | ifneq ($(1),host) 420 | $$(error expected target or host for argument 1, received $(1)) 421 | endif 422 | endif 423 | ifneq ($(2),ndebug) 424 | ifneq ($(2),debug) 425 | $$(error expected ndebug or debug for argument 2, received $(2)) 426 | endif 427 | endif 428 | ifneq ($(4),libart) 429 | ifneq ($(4),libopenjdkjvm) 430 | $$(error expected libart of libopenjdkjvm for argument 4, received $(4)) 431 | endif 432 | endif 433 | 434 | art_target_or_host := $(1) 435 | art_ndebug_or_debug := $(2) 436 | art_static_or_shared := $(3) 437 | 438 | include $$(CLEAR_VARS) 439 | LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION) 440 | ifeq ($$(art_ndebug_or_debug),ndebug) 441 | LOCAL_MODULE := $(4) 442 | ifeq ($$(art_target_or_host),target) 443 | LOCAL_FDO_SUPPORT := true 444 | endif 445 | else # debug 446 | LOCAL_MODULE := $(4)d 447 | endif 448 | 449 | LOCAL_MODULE_TAGS := optional 450 | 451 | ifeq ($$(art_static_or_shared),static) 452 | LOCAL_MODULE_CLASS := STATIC_LIBRARIES 453 | else 454 | LOCAL_MODULE_CLASS := SHARED_LIBRARIES 455 | endif 456 | 457 | ifeq ($(4),libart) 458 | ifeq ($$(art_target_or_host),target) 459 | LOCAL_SRC_FILES := $$(LIBART_TARGET_SRC_FILES) 460 | $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \ 461 | $$(eval LOCAL_SRC_FILES_$$(arch) := $$$$(LIBART_TARGET_SRC_FILES_$$(arch)))) 462 | else # host 463 | LOCAL_SRC_FILES := $$(LIBART_HOST_SRC_FILES) 464 | LOCAL_SRC_FILES_32 := $$(LIBART_HOST_SRC_FILES_32) 465 | LOCAL_SRC_FILES_64 := $$(LIBART_HOST_SRC_FILES_64) 466 | LOCAL_IS_HOST_MODULE := true 467 | endif 468 | else # libopenjdkjvm 469 | LOCAL_SRC_FILES := $$(LIBOPENJDKJVM_SRC_FILES) 470 | ifeq ($$(art_target_or_host),host) 471 | LOCAL_IS_HOST_MODULE := true 472 | endif 473 | endif 474 | 475 | ifeq ($(4),libart) 476 | GENERATED_SRC_DIR := $$(call local-generated-sources-dir) 477 | ENUM_OPERATOR_OUT_CC_FILES := $$(patsubst %.h,%_operator_out.cc,$$(LIBART_ENUM_OPERATOR_OUT_HEADER_FILES)) 478 | ENUM_OPERATOR_OUT_GEN := $$(addprefix $$(GENERATED_SRC_DIR)/,$$(ENUM_OPERATOR_OUT_CC_FILES)) 479 | 480 | $$(ENUM_OPERATOR_OUT_GEN): art/tools/generate-operator-out.py 481 | $$(ENUM_OPERATOR_OUT_GEN): PRIVATE_CUSTOM_TOOL = art/tools/generate-operator-out.py $(LOCAL_PATH) $$< > $$@ 482 | $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PATH)/%.h 483 | $$(transform-generated-source) 484 | 485 | LOCAL_GENERATED_SOURCES += $$(ENUM_OPERATOR_OUT_GEN) 486 | endif 487 | 488 | LOCAL_CFLAGS := $$(LIBART_CFLAGS) 489 | LOCAL_LDFLAGS := $$(LIBART_LDFLAGS) 490 | ifeq ($$(art_target_or_host),target) 491 | LOCAL_CFLAGS += $$(LIBART_TARGET_CFLAGS) 492 | LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS) 493 | $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \ 494 | $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch)))) 495 | else #host 496 | LOCAL_CFLAGS += $$(LIBART_HOST_CFLAGS) 497 | LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS) 498 | ifeq ($$(art_static_or_shared),static) 499 | LOCAL_LDFLAGS += -static 500 | endif 501 | endif 502 | 503 | # Clang usage 504 | ifeq ($$(art_target_or_host),target) 505 | $$(eval $$(call set-target-local-clang-vars)) 506 | $$(eval $$(call set-target-local-cflags-vars,$(2))) 507 | LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as 508 | LOCAL_CFLAGS_$(DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)" 509 | LOCAL_CFLAGS_$(2ND_DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)" 510 | else # host 511 | LOCAL_CLANG := $$(ART_HOST_CLANG) 512 | LOCAL_LDLIBS := $$(ART_HOST_LDLIBS) 513 | LOCAL_LDLIBS += -ldl -lpthread 514 | ifeq ($$(HOST_OS),linux) 515 | LOCAL_LDLIBS += -lrt 516 | endif 517 | LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) 518 | LOCAL_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES)" 519 | LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS) 520 | 521 | ifeq ($$(art_ndebug_or_debug),debug) 522 | LOCAL_CFLAGS += $$(ART_HOST_DEBUG_CFLAGS) 523 | else 524 | LOCAL_CFLAGS += $$(ART_HOST_NON_DEBUG_CFLAGS) 525 | endif 526 | LOCAL_MULTILIB := both 527 | endif 528 | 529 | LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) 530 | LOCAL_C_INCLUDES += art/cmdline 531 | LOCAL_C_INCLUDES += art/sigchainlib 532 | LOCAL_C_INCLUDES += art 533 | 534 | ifeq ($$(art_static_or_shared),static) 535 | LOCAL_STATIC_LIBRARIES := libnativehelper 536 | LOCAL_STATIC_LIBRARIES += libnativebridge 537 | LOCAL_STATIC_LIBRARIES += libnativeloader 538 | LOCAL_STATIC_LIBRARIES += libsigchain_dummy 539 | LOCAL_STATIC_LIBRARIES += libbacktrace 540 | LOCAL_STATIC_LIBRARIES += liblz4 541 | else 542 | LOCAL_SHARED_LIBRARIES := libnativehelper 543 | LOCAL_SHARED_LIBRARIES += libnativebridge 544 | LOCAL_SHARED_LIBRARIES += libnativeloader 545 | LOCAL_SHARED_LIBRARIES += libsigchain 546 | LOCAL_SHARED_LIBRARIES += libbacktrace 547 | LOCAL_SHARED_LIBRARIES += liblz4 548 | endif 549 | 550 | ifeq ($$(art_target_or_host),target) 551 | LOCAL_SHARED_LIBRARIES += libdl 552 | # ZipArchive support, the order matters here to get all symbols. 553 | LOCAL_STATIC_LIBRARIES := libziparchive libz libbase 554 | # For android::FileMap used by libziparchive. 555 | LOCAL_SHARED_LIBRARIES += libutils 556 | # For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted. 557 | LOCAL_SHARED_LIBRARIES += libcutils 558 | else # host 559 | ifeq ($$(art_static_or_shared),static) 560 | LOCAL_STATIC_LIBRARIES += libziparchive-host libz 561 | # For ashmem_create_region. 562 | LOCAL_STATIC_LIBRARIES += libcutils 563 | else 564 | LOCAL_SHARED_LIBRARIES += libziparchive-host libz-host 565 | # For ashmem_create_region. 566 | LOCAL_SHARED_LIBRARIES += libcutils 567 | endif 568 | endif 569 | 570 | ifeq ($(4),libopenjdkjvm) 571 | ifeq ($$(art_ndebug_or_debug),ndebug) 572 | LOCAL_SHARED_LIBRARIES += libart 573 | else 574 | LOCAL_SHARED_LIBRARIES += libartd 575 | endif 576 | LOCAL_NOTICE_FILE := $(LOCAL_PATH)/openjdkjvm/NOTICE 577 | endif 578 | LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk 579 | LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk 580 | 581 | ifeq ($$(art_target_or_host),target) 582 | LOCAL_MODULE_TARGET_ARCH := $$(ART_TARGET_SUPPORTED_ARCH) 583 | endif 584 | 585 | LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE) 586 | 587 | ifeq ($$(art_target_or_host),target) 588 | ifneq ($$(art_ndebug_or_debug),debug) 589 | # Leave the symbols in the shared library so that stack unwinders can 590 | # produce meaningful name resolution. 591 | LOCAL_STRIP_MODULE := keep_symbols 592 | endif 593 | include $$(BUILD_SHARED_LIBRARY) 594 | else # host 595 | ifeq ($$(art_static_or_shared),static) 596 | include $$(BUILD_HOST_STATIC_LIBRARY) 597 | else 598 | include $$(BUILD_HOST_SHARED_LIBRARY) 599 | endif 600 | endif 601 | 602 | # Clear locally defined variables. 603 | GENERATED_SRC_DIR := 604 | ENUM_OPERATOR_OUT_CC_FILES := 605 | ENUM_OPERATOR_OUT_GEN := 606 | art_target_or_host := 607 | art_ndebug_or_debug := 608 | art_static_or_shared := 609 | endef 610 | 611 | # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since 612 | # they are used to cross compile for the target. 613 | ifeq ($(ART_BUILD_HOST_NDEBUG),true) 614 | $(eval $(call build-runtime-library,host,ndebug,shared,libart)) 615 | $(eval $(call build-runtime-library,host,ndebug,shared,libopenjdkjvm)) 616 | ifeq ($(ART_BUILD_HOST_STATIC),true) 617 | $(eval $(call build-runtime-library,host,ndebug,static,libart)) 618 | $(eval $(call build-runtime-library,host,ndebug,static,libopenjdkjvm)) 619 | endif 620 | endif 621 | ifeq ($(ART_BUILD_HOST_DEBUG),true) 622 | $(eval $(call build-runtime-library,host,debug,shared,libart)) 623 | $(eval $(call build-runtime-library,host,debug,shared,libopenjdkjvm)) 624 | ifeq ($(ART_BUILD_HOST_STATIC),true) 625 | $(eval $(call build-runtime-library,host,debug,static,libart)) 626 | $(eval $(call build-runtime-library,host,debug,static,libopenjdkjvm)) 627 | endif 628 | endif 629 | 630 | ifeq ($(ART_BUILD_TARGET_NDEBUG),true) 631 | # $(error $(call build-runtime-library,target,ndebug)) 632 | $(eval $(call build-runtime-library,target,ndebug,shared,libart)) 633 | $(eval $(call build-runtime-library,target,ndebug,shared,libopenjdkjvm)) 634 | endif 635 | ifeq ($(ART_BUILD_TARGET_DEBUG),true) 636 | $(eval $(call build-runtime-library,target,debug,shared,libart)) 637 | $(eval $(call build-runtime-library,target,debug,shared,libopenjdkjvm)) 638 | endif 639 | 640 | # Clear locally defined variables. 641 | LOCAL_PATH := 642 | LIBART_COMMON_SRC_FILES := 643 | LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES := 644 | LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := 645 | 2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := 646 | LIBART_HOST_LDFLAGS := 647 | LIBART_TARGET_LDFLAGS := 648 | LIBART_TARGET_LDFLAGS_arm := 649 | LIBART_TARGET_LDFLAGS_arm64 := 650 | LIBART_TARGET_LDFLAGS_x86 := 651 | LIBART_TARGET_LDFLAGS_x86_64 := 652 | LIBART_TARGET_LDFLAGS_mips := 653 | LIBART_TARGET_LDFLAGS_mips64 := 654 | LIBART_TARGET_SRC_FILES := 655 | LIBART_TARGET_SRC_FILES_arm := 656 | LIBART_TARGET_SRC_FILES_arm64 := 657 | LIBART_TARGET_SRC_FILES_x86 := 658 | LIBART_TARGET_SRC_FILES_x86_64 := 659 | LIBART_TARGET_SRC_FILES_mips := 660 | LIBART_TARGET_SRC_FILES_mips64 := 661 | LIBART_HOST_SRC_FILES := 662 | LIBART_HOST_SRC_FILES_32 := 663 | LIBART_HOST_SRC_FILES_64 := 664 | LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := 665 | LIBART_CFLAGS := 666 | LIBART_TARGET_CFLAGS := 667 | LIBART_HOST_CFLAGS := 668 | build-runtime-library := 669 | -------------------------------------------------------------------------------- /art/runtime/art_method.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "art_method.h" 18 | 19 | #include "arch/context.h" 20 | #include "art_field-inl.h" 21 | #include "art_method-inl.h" 22 | #include "base/stringpiece.h" 23 | #include "class_linker-inl.h" 24 | #include "debugger.h" 25 | #include "dex_file-inl.h" 26 | #include "dex_instruction.h" 27 | #include "entrypoints/runtime_asm_entrypoints.h" 28 | #include "gc/accounting/card_table-inl.h" 29 | #include "interpreter/interpreter.h" 30 | #include "jit/jit.h" 31 | #include "jit/jit_code_cache.h" 32 | #include "jit/profiling_info.h" 33 | #include "jni_internal.h" 34 | #include "mirror/abstract_method.h" 35 | #include "mirror/class-inl.h" 36 | #include "mirror/object_array-inl.h" 37 | #include "mirror/object-inl.h" 38 | #include "mirror/string.h" 39 | #include "oat_file-inl.h" 40 | #include "scoped_thread_state_change.h" 41 | #include "well_known_classes.h" 42 | 43 | /* AUPK Begin */ 44 | #include 45 | #include 46 | #include "runtime.h" 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include "aupk.h" 64 | /* AUPK End */ 65 | namespace art 66 | { 67 | 68 | extern "C" void art_quick_invoke_stub(ArtMethod *, uint32_t *, uint32_t, Thread *, JValue *, 69 | const char *); 70 | extern "C" void art_quick_invoke_static_stub(ArtMethod *, uint32_t *, uint32_t, Thread *, JValue *, 71 | const char *); 72 | 73 | ArtMethod *ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable &soa, 74 | jobject jlr_method) 75 | { 76 | auto *abstract_method = soa.Decode(jlr_method); 77 | DCHECK(abstract_method != nullptr); 78 | return abstract_method->GetArtMethod(); 79 | } 80 | 81 | mirror::String *ArtMethod::GetNameAsString(Thread *self) 82 | { 83 | CHECK(!IsProxyMethod()); 84 | StackHandleScope<1> hs(self); 85 | Handle dex_cache(hs.NewHandle(GetDexCache())); 86 | auto *dex_file = dex_cache->GetDexFile(); 87 | uint32_t dex_method_idx = GetDexMethodIndex(); 88 | const DexFile::MethodId &method_id = dex_file->GetMethodId(dex_method_idx); 89 | return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_, 90 | dex_cache); 91 | } 92 | 93 | void ArtMethod::ThrowInvocationTimeError() 94 | { 95 | DCHECK(!IsInvokable()); 96 | // NOTE: IsDefaultConflicting must be first since the actual method might or might not be abstract 97 | // due to the way we select it. 98 | if (IsDefaultConflicting()) 99 | { 100 | ThrowIncompatibleClassChangeErrorForMethodConflict(this); 101 | } 102 | else 103 | { 104 | DCHECK(IsAbstract()); 105 | ThrowAbstractMethodError(this); 106 | } 107 | } 108 | 109 | InvokeType ArtMethod::GetInvokeType() 110 | { 111 | // TODO: kSuper? 112 | if (IsStatic()) 113 | { 114 | return kStatic; 115 | } 116 | else if (GetDeclaringClass()->IsInterface()) 117 | { 118 | return kInterface; 119 | } 120 | else if (IsDirect()) 121 | { 122 | return kDirect; 123 | } 124 | else 125 | { 126 | return kVirtual; 127 | } 128 | } 129 | 130 | size_t ArtMethod::NumArgRegisters(const StringPiece &shorty) 131 | { 132 | CHECK_LE(1U, shorty.length()); 133 | uint32_t num_registers = 0; 134 | for (size_t i = 1; i < shorty.length(); ++i) 135 | { 136 | char ch = shorty[i]; 137 | if (ch == 'D' || ch == 'J') 138 | { 139 | num_registers += 2; 140 | } 141 | else 142 | { 143 | num_registers += 1; 144 | } 145 | } 146 | return num_registers; 147 | } 148 | 149 | bool ArtMethod::HasSameNameAndSignature(ArtMethod *other) 150 | { 151 | ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature"); 152 | const DexFile *dex_file = GetDexFile(); 153 | const DexFile::MethodId &mid = dex_file->GetMethodId(GetDexMethodIndex()); 154 | if (GetDexCache() == other->GetDexCache()) 155 | { 156 | const DexFile::MethodId &mid2 = dex_file->GetMethodId(other->GetDexMethodIndex()); 157 | return mid.name_idx_ == mid2.name_idx_ && mid.proto_idx_ == mid2.proto_idx_; 158 | } 159 | const DexFile *dex_file2 = other->GetDexFile(); 160 | const DexFile::MethodId &mid2 = dex_file2->GetMethodId(other->GetDexMethodIndex()); 161 | if (!DexFileStringEquals(dex_file, mid.name_idx_, dex_file2, mid2.name_idx_)) 162 | { 163 | return false; // Name mismatch. 164 | } 165 | return dex_file->GetMethodSignature(mid) == dex_file2->GetMethodSignature(mid2); 166 | } 167 | 168 | ArtMethod *ArtMethod::FindOverriddenMethod(size_t pointer_size) 169 | { 170 | if (IsStatic()) 171 | { 172 | return nullptr; 173 | } 174 | mirror::Class *declaring_class = GetDeclaringClass(); 175 | mirror::Class *super_class = declaring_class->GetSuperClass(); 176 | uint16_t method_index = GetMethodIndex(); 177 | ArtMethod *result = nullptr; 178 | // Did this method override a super class method? If so load the result from the super class' 179 | // vtable 180 | if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) 181 | { 182 | result = super_class->GetVTableEntry(method_index, pointer_size); 183 | } 184 | else 185 | { 186 | // Method didn't override superclass method so search interfaces 187 | if (IsProxyMethod()) 188 | { 189 | result = mirror::DexCache::GetElementPtrSize(GetDexCacheResolvedMethods(pointer_size), 190 | GetDexMethodIndex(), 191 | pointer_size); 192 | CHECK_EQ(result, 193 | Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this)); 194 | } 195 | else 196 | { 197 | mirror::IfTable *iftable = GetDeclaringClass()->GetIfTable(); 198 | for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) 199 | { 200 | mirror::Class *interface = iftable->GetInterface(i); 201 | for (ArtMethod &interface_method : interface->GetVirtualMethods(pointer_size)) 202 | { 203 | if (HasSameNameAndSignature(interface_method.GetInterfaceMethodIfProxy(pointer_size))) 204 | { 205 | result = &interface_method; 206 | break; 207 | } 208 | } 209 | } 210 | } 211 | } 212 | DCHECK(result == nullptr || 213 | GetInterfaceMethodIfProxy(pointer_size)->HasSameNameAndSignature(result->GetInterfaceMethodIfProxy(pointer_size))); 214 | return result; 215 | } 216 | 217 | uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile &other_dexfile, 218 | uint32_t name_and_signature_idx) 219 | { 220 | const DexFile *dexfile = GetDexFile(); 221 | const uint32_t dex_method_idx = GetDexMethodIndex(); 222 | const DexFile::MethodId &mid = dexfile->GetMethodId(dex_method_idx); 223 | const DexFile::MethodId &name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx); 224 | DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid)); 225 | DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid)); 226 | if (dexfile == &other_dexfile) 227 | { 228 | return dex_method_idx; 229 | } 230 | const char *mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); 231 | const DexFile::TypeId *other_type_id = other_dexfile.FindTypeId(mid_declaring_class_descriptor); 232 | if (other_type_id != nullptr) 233 | { 234 | const DexFile::MethodId *other_mid = other_dexfile.FindMethodId( 235 | *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_), 236 | other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_)); 237 | if (other_mid != nullptr) 238 | { 239 | return other_dexfile.GetIndexForMethodId(*other_mid); 240 | } 241 | } 242 | return DexFile::kDexNoIndex; 243 | } 244 | 245 | uint32_t ArtMethod::FindCatchBlock(Handle exception_type, 246 | uint32_t dex_pc, bool *has_no_move_exception) 247 | { 248 | const DexFile::CodeItem *code_item = GetCodeItem(); 249 | // Set aside the exception while we resolve its type. 250 | Thread *self = Thread::Current(); 251 | StackHandleScope<1> hs(self); 252 | Handle exception(hs.NewHandle(self->GetException())); 253 | self->ClearException(); 254 | // Default to handler not found. 255 | uint32_t found_dex_pc = DexFile::kDexNoIndex; 256 | // Iterate over the catch handlers associated with dex_pc. 257 | size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); 258 | for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) 259 | { 260 | uint16_t iter_type_idx = it.GetHandlerTypeIndex(); 261 | // Catch all case 262 | if (iter_type_idx == DexFile::kDexNoIndex16) 263 | { 264 | found_dex_pc = it.GetHandlerAddress(); 265 | break; 266 | } 267 | // Does this catch exception type apply? 268 | mirror::Class *iter_exception_type = GetClassFromTypeIndex(iter_type_idx, 269 | true /* resolve */, 270 | pointer_size); 271 | if (UNLIKELY(iter_exception_type == nullptr)) 272 | { 273 | // Now have a NoClassDefFoundError as exception. Ignore in case the exception class was 274 | // removed by a pro-guard like tool. 275 | // Note: this is not RI behavior. RI would have failed when loading the class. 276 | self->ClearException(); 277 | // Delete any long jump context as this routine is called during a stack walk which will 278 | // release its in use context at the end. 279 | delete self->GetLongJumpContext(); 280 | LOG(WARNING) << "Unresolved exception class when finding catch block: " 281 | << DescriptorToDot(GetTypeDescriptorFromTypeIdx(iter_type_idx)); 282 | } 283 | else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) 284 | { 285 | found_dex_pc = it.GetHandlerAddress(); 286 | break; 287 | } 288 | } 289 | if (found_dex_pc != DexFile::kDexNoIndex) 290 | { 291 | const Instruction *first_catch_instr = 292 | Instruction::At(&code_item->insns_[found_dex_pc]); 293 | *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION); 294 | } 295 | // Put the exception back. 296 | if (exception.Get() != nullptr) 297 | { 298 | self->SetException(exception.Get()); 299 | } 300 | return found_dex_pc; 301 | } 302 | 303 | void ArtMethod::Invoke(Thread *self, uint32_t *args, uint32_t args_size, JValue *result, 304 | const char *shorty) 305 | { 306 | /* AUPK Begin */ 307 | bool isFakeInvokeMethod = Aupk::isFakeInvoke(self, this); 308 | /* AUPK End */ 309 | 310 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) 311 | { 312 | ThrowStackOverflowError(self); 313 | return; 314 | } 315 | 316 | if (kIsDebugBuild) 317 | { 318 | self->AssertThreadSuspensionIsAllowable(); 319 | CHECK_EQ(kRunnable, self->GetState()); 320 | CHECK_STREQ(GetInterfaceMethodIfProxy(sizeof(void *))->GetShorty(), shorty); 321 | } 322 | 323 | // Push a transition back into managed code onto the linked list in thread. 324 | ManagedStack fragment; 325 | self->PushManagedStackFragment(&fragment); 326 | Runtime *runtime = Runtime::Current(); 327 | // Call the invoke stub, passing everything as arguments. 328 | // If the runtime is not yet started or it is required by the debugger, then perform the 329 | // Invocation by the interpreter, explicitly forcing interpretation over JIT to prevent 330 | // cycling around the various JIT/Interpreter methods that handle method invocation. 331 | 332 | /* AUPK Begin */ 333 | // 当isFakeInvokeMethod==true时且不为native方法时,使其强制走解释器 334 | //if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this))) 335 | // if (isFakeInvokeMethod) 336 | // { 337 | // LOG(INFO) << "is fake invoke:"<< "true--"<IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this)) || isFakeInvokeMethod) 345 | { 346 | /* AUPK End */ 347 | if (IsStatic()) 348 | { 349 | art::interpreter::EnterInterpreterFromInvoke( 350 | self, this, nullptr, args, result, /*stay_in_interpreter*/ true); 351 | } 352 | else 353 | { 354 | 355 | mirror::Object *receiver = 356 | reinterpret_cast *>(&args[0])->AsMirrorPtr(); 357 | art::interpreter::EnterInterpreterFromInvoke( 358 | self, this, receiver, args + 1, result, /*stay_in_interpreter*/ true); 359 | } 360 | } 361 | else 362 | { 363 | 364 | DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), sizeof(void *)); 365 | 366 | constexpr bool kLogInvocationStartAndReturn = false; 367 | bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr; 368 | if (LIKELY(have_quick_code)) 369 | { 370 | if (kLogInvocationStartAndReturn) 371 | { 372 | LOG(INFO) << StringPrintf( 373 | "Invoking '%s' quick code=%p static=%d", PrettyMethod(this).c_str(), 374 | GetEntryPointFromQuickCompiledCode(), static_cast(IsStatic() ? 1 : 0)); 375 | } 376 | 377 | // Ensure that we won't be accidentally calling quick compiled code when -Xint. 378 | if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) 379 | { 380 | CHECK(!runtime->UseJitCompilation()); 381 | const void *oat_quick_code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(this); 382 | CHECK(oat_quick_code == nullptr || oat_quick_code != GetEntryPointFromQuickCompiledCode()) 383 | << "Don't call compiled code when -Xint " << PrettyMethod(this); 384 | } 385 | 386 | if (!IsStatic()) 387 | { 388 | (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty); 389 | } 390 | else 391 | { 392 | (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty); 393 | } 394 | if (UNLIKELY(self->GetException() == Thread::GetDeoptimizationException())) 395 | { 396 | // Unusual case where we were running generated code and an 397 | // exception was thrown to force the activations to be removed from the 398 | // stack. Continue execution in the interpreter. 399 | self->DeoptimizeWithDeoptimizationException(result); 400 | } 401 | if (kLogInvocationStartAndReturn) 402 | { 403 | LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(), 404 | GetEntryPointFromQuickCompiledCode()); 405 | } 406 | } 407 | else 408 | { 409 | LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null"; 410 | if (result != nullptr) 411 | { 412 | result->SetJ(0); 413 | } 414 | } 415 | } 416 | // Pop transition. 417 | self->PopManagedStackFragment(fragment); 418 | } 419 | 420 | void ArtMethod::RegisterNative(const void *native_method, bool is_fast) 421 | { 422 | CHECK(IsNative()) << PrettyMethod(this); 423 | CHECK(!IsFastNative()) << PrettyMethod(this); 424 | CHECK(native_method != nullptr) << PrettyMethod(this); 425 | if (is_fast) 426 | { 427 | SetAccessFlags(GetAccessFlags() | kAccFastNative); 428 | } 429 | SetEntryPointFromJni(native_method); 430 | } 431 | 432 | void ArtMethod::UnregisterNative() 433 | { 434 | CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this); 435 | // restore stub to lookup native pointer via dlsym 436 | RegisterNative(GetJniDlsymLookupStub(), false); 437 | } 438 | 439 | bool ArtMethod::IsOverridableByDefaultMethod() 440 | { 441 | return GetDeclaringClass()->IsInterface(); 442 | } 443 | 444 | bool ArtMethod::EqualParameters(Handle> params) 445 | { 446 | auto *dex_cache = GetDexCache(); 447 | auto *dex_file = dex_cache->GetDexFile(); 448 | const auto &method_id = dex_file->GetMethodId(GetDexMethodIndex()); 449 | const auto &proto_id = dex_file->GetMethodPrototype(method_id); 450 | const DexFile::TypeList *proto_params = dex_file->GetProtoParameters(proto_id); 451 | auto count = proto_params != nullptr ? proto_params->Size() : 0u; 452 | auto param_len = params.Get() != nullptr ? params->GetLength() : 0u; 453 | if (param_len != count) 454 | { 455 | return false; 456 | } 457 | auto *cl = Runtime::Current()->GetClassLinker(); 458 | for (size_t i = 0; i < count; ++i) 459 | { 460 | auto type_idx = proto_params->GetTypeItem(i).type_idx_; 461 | auto *type = cl->ResolveType(type_idx, this); 462 | if (type == nullptr) 463 | { 464 | Thread::Current()->AssertPendingException(); 465 | return false; 466 | } 467 | if (type != params->GetWithoutChecks(i)) 468 | { 469 | return false; 470 | } 471 | } 472 | return true; 473 | } 474 | 475 | const uint8_t *ArtMethod::GetQuickenedInfo() 476 | { 477 | bool found = false; 478 | OatFile::OatMethod oat_method = 479 | Runtime::Current()->GetClassLinker()->FindOatMethodFor(this, &found); 480 | if (!found || (oat_method.GetQuickCode() != nullptr)) 481 | { 482 | return nullptr; 483 | } 484 | return oat_method.GetVmapTable(); 485 | } 486 | 487 | const OatQuickMethodHeader *ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) 488 | { 489 | // Our callers should make sure they don't pass the instrumentation exit pc, 490 | // as this method does not look at the side instrumentation stack. 491 | DCHECK_NE(pc, reinterpret_cast(GetQuickInstrumentationExitPc())); 492 | 493 | if (IsRuntimeMethod()) 494 | { 495 | return nullptr; 496 | } 497 | 498 | Runtime *runtime = Runtime::Current(); 499 | const void *existing_entry_point = GetEntryPointFromQuickCompiledCode(); 500 | CHECK(existing_entry_point != nullptr) << PrettyMethod(this) << "@" << this; 501 | ClassLinker *class_linker = runtime->GetClassLinker(); 502 | 503 | if (class_linker->IsQuickGenericJniStub(existing_entry_point)) 504 | { 505 | // The generic JNI does not have any method header. 506 | return nullptr; 507 | } 508 | 509 | if (existing_entry_point == GetQuickProxyInvokeHandler()) 510 | { 511 | DCHECK(IsProxyMethod() && !IsConstructor()); 512 | // The proxy entry point does not have any method header. 513 | return nullptr; 514 | } 515 | 516 | // Check whether the current entry point contains this pc. 517 | if (!class_linker->IsQuickResolutionStub(existing_entry_point) && 518 | !class_linker->IsQuickToInterpreterBridge(existing_entry_point)) 519 | { 520 | OatQuickMethodHeader *method_header = 521 | OatQuickMethodHeader::FromEntryPoint(existing_entry_point); 522 | 523 | if (method_header->Contains(pc)) 524 | { 525 | return method_header; 526 | } 527 | } 528 | 529 | // Check whether the pc is in the JIT code cache. 530 | jit::Jit *jit = Runtime::Current()->GetJit(); 531 | if (jit != nullptr) 532 | { 533 | jit::JitCodeCache *code_cache = jit->GetCodeCache(); 534 | OatQuickMethodHeader *method_header = code_cache->LookupMethodHeader(pc, this); 535 | if (method_header != nullptr) 536 | { 537 | DCHECK(method_header->Contains(pc)); 538 | return method_header; 539 | } 540 | else 541 | { 542 | DCHECK(!code_cache->ContainsPc(reinterpret_cast(pc))) 543 | << PrettyMethod(this) 544 | << ", pc=" << std::hex << pc 545 | << ", entry_point=" << std::hex << reinterpret_cast(existing_entry_point) 546 | << ", copy=" << std::boolalpha << IsCopied() 547 | << ", proxy=" << std::boolalpha << IsProxyMethod(); 548 | } 549 | } 550 | 551 | // The code has to be in an oat file. 552 | bool found; 553 | OatFile::OatMethod oat_method = class_linker->FindOatMethodFor(this, &found); 554 | if (!found) 555 | { 556 | if (class_linker->IsQuickResolutionStub(existing_entry_point)) 557 | { 558 | // We are running the generic jni stub, but the entry point of the method has not 559 | // been updated yet. 560 | DCHECK_EQ(pc, 0u) << "Should be a downcall"; 561 | DCHECK(IsNative()); 562 | return nullptr; 563 | } 564 | if (existing_entry_point == GetQuickInstrumentationEntryPoint()) 565 | { 566 | // We are running the generic jni stub, but the method is being instrumented. 567 | DCHECK_EQ(pc, 0u) << "Should be a downcall"; 568 | DCHECK(IsNative()); 569 | return nullptr; 570 | } 571 | // Only for unit tests. 572 | // TODO(ngeoffray): Update these tests to pass the right pc? 573 | return OatQuickMethodHeader::FromEntryPoint(existing_entry_point); 574 | } 575 | const void *oat_entry_point = oat_method.GetQuickCode(); 576 | if (oat_entry_point == nullptr || class_linker->IsQuickGenericJniStub(oat_entry_point)) 577 | { 578 | DCHECK(IsNative()) << PrettyMethod(this); 579 | return nullptr; 580 | } 581 | 582 | OatQuickMethodHeader *method_header = OatQuickMethodHeader::FromEntryPoint(oat_entry_point); 583 | if (pc == 0) 584 | { 585 | // This is a downcall, it can only happen for a native method. 586 | DCHECK(IsNative()); 587 | return method_header; 588 | } 589 | 590 | DCHECK(method_header->Contains(pc)) 591 | << PrettyMethod(this) 592 | << std::hex << pc << " " << oat_entry_point 593 | << " " << (uintptr_t)(method_header->code_ + method_header->code_size_); 594 | return method_header; 595 | } 596 | 597 | bool ArtMethod::HasAnyCompiledCode() 598 | { 599 | // Check whether the JIT has compiled it. 600 | jit::Jit *jit = Runtime::Current()->GetJit(); 601 | if (jit != nullptr && jit->GetCodeCache()->ContainsMethod(this)) 602 | { 603 | return true; 604 | } 605 | 606 | // Check whether we have AOT code. 607 | return Runtime::Current()->GetClassLinker()->GetOatMethodQuickCodeFor(this) != nullptr; 608 | } 609 | 610 | void ArtMethod::CopyFrom(ArtMethod *src, size_t image_pointer_size) 611 | { 612 | memcpy(reinterpret_cast(this), reinterpret_cast(src), 613 | Size(image_pointer_size)); 614 | declaring_class_ = GcRoot(const_cast(src)->GetDeclaringClass()); 615 | 616 | // If the entry point of the method we are copying from is from JIT code, we just 617 | // put the entry point of the new method to interpreter. We could set the entry point 618 | // to the JIT code, but this would require taking the JIT code cache lock to notify 619 | // it, which we do not want at this level. 620 | Runtime *runtime = Runtime::Current(); 621 | if (runtime->UseJitCompilation()) 622 | { 623 | if (runtime->GetJit()->GetCodeCache()->ContainsPc(GetEntryPointFromQuickCompiledCode())) 624 | { 625 | SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), image_pointer_size); 626 | } 627 | } 628 | // Clear the profiling info for the same reasons as the JIT code. 629 | if (!src->IsNative()) 630 | { 631 | SetProfilingInfoPtrSize(nullptr, image_pointer_size); 632 | } 633 | // Clear hotness to let the JIT properly decide when to compile this method. 634 | hotness_count_ = 0; 635 | } 636 | 637 | } // namespace art 638 | -------------------------------------------------------------------------------- /art/runtime/art_method.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef ART_RUNTIME_ART_METHOD_H_ 18 | #define ART_RUNTIME_ART_METHOD_H_ 19 | 20 | #include "base/bit_utils.h" 21 | #include "base/casts.h" 22 | #include "dex_file.h" 23 | #include "gc_root.h" 24 | #include "invoke_type.h" 25 | #include "method_reference.h" 26 | #include "modifiers.h" 27 | #include "mirror/object.h" 28 | #include "read_barrier_option.h" 29 | #include "stack.h" 30 | #include "utils.h" 31 | 32 | namespace art { 33 | 34 | union JValue; 35 | class OatQuickMethodHeader; 36 | class ProfilingInfo; 37 | class ScopedObjectAccessAlreadyRunnable; 38 | class StringPiece; 39 | class ShadowFrame; 40 | 41 | namespace mirror { 42 | class Array; 43 | class Class; 44 | class IfTable; 45 | class PointerArray; 46 | } // namespace mirror 47 | 48 | // Table to resolve IMT conflicts at runtime. The table is attached to 49 | // the jni entrypoint of IMT conflict ArtMethods. 50 | // The table contains a list of pairs of { interface_method, implementation_method } 51 | // with the last entry being null to make an assembly implementation of a lookup 52 | // faster. 53 | class ImtConflictTable { 54 | enum MethodIndex { 55 | kMethodInterface, 56 | kMethodImplementation, 57 | kMethodCount, // Number of elements in enum. 58 | }; 59 | 60 | public: 61 | // Build a new table copying `other` and adding the new entry formed of 62 | // the pair { `interface_method`, `implementation_method` } 63 | ImtConflictTable(ImtConflictTable* other, 64 | ArtMethod* interface_method, 65 | ArtMethod* implementation_method, 66 | size_t pointer_size) { 67 | const size_t count = other->NumEntries(pointer_size); 68 | for (size_t i = 0; i < count; ++i) { 69 | SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size)); 70 | SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size)); 71 | } 72 | SetInterfaceMethod(count, pointer_size, interface_method); 73 | SetImplementationMethod(count, pointer_size, implementation_method); 74 | // Add the null marker. 75 | SetInterfaceMethod(count + 1, pointer_size, nullptr); 76 | SetImplementationMethod(count + 1, pointer_size, nullptr); 77 | } 78 | 79 | // num_entries excludes the header. 80 | ImtConflictTable(size_t num_entries, size_t pointer_size) { 81 | SetInterfaceMethod(num_entries, pointer_size, nullptr); 82 | SetImplementationMethod(num_entries, pointer_size, nullptr); 83 | } 84 | 85 | // Set an entry at an index. 86 | void SetInterfaceMethod(size_t index, size_t pointer_size, ArtMethod* method) { 87 | SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method); 88 | } 89 | 90 | void SetImplementationMethod(size_t index, size_t pointer_size, ArtMethod* method) { 91 | SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method); 92 | } 93 | 94 | ArtMethod* GetInterfaceMethod(size_t index, size_t pointer_size) const { 95 | return GetMethod(index * kMethodCount + kMethodInterface, pointer_size); 96 | } 97 | 98 | ArtMethod* GetImplementationMethod(size_t index, size_t pointer_size) const { 99 | return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size); 100 | } 101 | 102 | // Return true if two conflict tables are the same. 103 | bool Equals(ImtConflictTable* other, size_t pointer_size) const { 104 | size_t num = NumEntries(pointer_size); 105 | if (num != other->NumEntries(pointer_size)) { 106 | return false; 107 | } 108 | for (size_t i = 0; i < num; ++i) { 109 | if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) || 110 | GetImplementationMethod(i, pointer_size) != 111 | other->GetImplementationMethod(i, pointer_size)) { 112 | return false; 113 | } 114 | } 115 | return true; 116 | } 117 | 118 | // Visit all of the entries. 119 | // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod* 120 | // and also returns one. The order is . 121 | template 122 | void Visit(const Visitor& visitor, size_t pointer_size) NO_THREAD_SAFETY_ANALYSIS { 123 | uint32_t table_index = 0; 124 | for (;;) { 125 | ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size); 126 | if (interface_method == nullptr) { 127 | break; 128 | } 129 | ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size); 130 | auto input = std::make_pair(interface_method, implementation_method); 131 | std::pair updated = visitor(input); 132 | if (input.first != updated.first) { 133 | SetInterfaceMethod(table_index, pointer_size, updated.first); 134 | } 135 | if (input.second != updated.second) { 136 | SetImplementationMethod(table_index, pointer_size, updated.second); 137 | } 138 | ++table_index; 139 | } 140 | } 141 | 142 | // Lookup the implementation ArtMethod associated to `interface_method`. Return null 143 | // if not found. 144 | ArtMethod* Lookup(ArtMethod* interface_method, size_t pointer_size) const { 145 | uint32_t table_index = 0; 146 | for (;;) { 147 | ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size); 148 | if (current_interface_method == nullptr) { 149 | break; 150 | } 151 | if (current_interface_method == interface_method) { 152 | return GetImplementationMethod(table_index, pointer_size); 153 | } 154 | ++table_index; 155 | } 156 | return nullptr; 157 | } 158 | 159 | // Compute the number of entries in this table. 160 | size_t NumEntries(size_t pointer_size) const { 161 | uint32_t table_index = 0; 162 | while (GetInterfaceMethod(table_index, pointer_size) != nullptr) { 163 | ++table_index; 164 | } 165 | return table_index; 166 | } 167 | 168 | // Compute the size in bytes taken by this table. 169 | size_t ComputeSize(size_t pointer_size) const { 170 | // Add the end marker. 171 | return ComputeSize(NumEntries(pointer_size), pointer_size); 172 | } 173 | 174 | // Compute the size in bytes needed for copying the given `table` and add 175 | // one more entry. 176 | static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, size_t pointer_size) { 177 | return table->ComputeSize(pointer_size) + EntrySize(pointer_size); 178 | } 179 | 180 | // Compute size with a fixed number of entries. 181 | static size_t ComputeSize(size_t num_entries, size_t pointer_size) { 182 | return (num_entries + 1) * EntrySize(pointer_size); // Add one for null terminator. 183 | } 184 | 185 | static size_t EntrySize(size_t pointer_size) { 186 | return pointer_size * static_cast(kMethodCount); 187 | } 188 | 189 | private: 190 | ArtMethod* GetMethod(size_t index, size_t pointer_size) const { 191 | if (pointer_size == 8) { 192 | return reinterpret_cast(static_cast(data64_[index])); 193 | } else { 194 | DCHECK_EQ(pointer_size, 4u); 195 | return reinterpret_cast(static_cast(data32_[index])); 196 | } 197 | } 198 | 199 | void SetMethod(size_t index, size_t pointer_size, ArtMethod* method) { 200 | if (pointer_size == 8) { 201 | data64_[index] = dchecked_integral_cast(reinterpret_cast(method)); 202 | } else { 203 | DCHECK_EQ(pointer_size, 4u); 204 | data32_[index] = dchecked_integral_cast(reinterpret_cast(method)); 205 | } 206 | } 207 | 208 | // Array of entries that the assembly stubs will iterate over. Note that this is 209 | // not fixed size, and we allocate data prior to calling the constructor 210 | // of ImtConflictTable. 211 | union { 212 | uint32_t data32_[0]; 213 | uint64_t data64_[0]; 214 | }; 215 | 216 | DISALLOW_COPY_AND_ASSIGN(ImtConflictTable); 217 | }; 218 | 219 | class ArtMethod FINAL { 220 | public: 221 | ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0), 222 | method_index_(0) { } 223 | 224 | ArtMethod(ArtMethod* src, size_t image_pointer_size) { 225 | CopyFrom(src, image_pointer_size); 226 | } 227 | 228 | static ArtMethod* FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, 229 | jobject jlr_method) 230 | SHARED_REQUIRES(Locks::mutator_lock_); 231 | 232 | template 233 | ALWAYS_INLINE mirror::Class* GetDeclaringClass() SHARED_REQUIRES(Locks::mutator_lock_); 234 | 235 | template 236 | ALWAYS_INLINE mirror::Class* GetDeclaringClassUnchecked() 237 | SHARED_REQUIRES(Locks::mutator_lock_); 238 | 239 | void SetDeclaringClass(mirror::Class *new_declaring_class) 240 | SHARED_REQUIRES(Locks::mutator_lock_); 241 | 242 | bool CASDeclaringClass(mirror::Class* expected_class, mirror::Class* desired_class) 243 | SHARED_REQUIRES(Locks::mutator_lock_); 244 | 245 | static MemberOffset DeclaringClassOffset() { 246 | return MemberOffset(OFFSETOF_MEMBER(ArtMethod, declaring_class_)); 247 | } 248 | 249 | // Note: GetAccessFlags acquires the mutator lock in debug mode to check that it is not called for 250 | // a proxy method. 251 | template 252 | ALWAYS_INLINE uint32_t GetAccessFlags(); 253 | 254 | void SetAccessFlags(uint32_t new_access_flags) { 255 | // Not called within a transaction. 256 | access_flags_ = new_access_flags; 257 | } 258 | 259 | // Approximate what kind of method call would be used for this method. 260 | InvokeType GetInvokeType() SHARED_REQUIRES(Locks::mutator_lock_); 261 | 262 | // Returns true if the method is declared public. 263 | bool IsPublic() { 264 | return (GetAccessFlags() & kAccPublic) != 0; 265 | } 266 | 267 | // Returns true if the method is declared private. 268 | bool IsPrivate() { 269 | return (GetAccessFlags() & kAccPrivate) != 0; 270 | } 271 | 272 | // Returns true if the method is declared static. 273 | bool IsStatic() { 274 | return (GetAccessFlags() & kAccStatic) != 0; 275 | } 276 | 277 | // Returns true if the method is a constructor. 278 | bool IsConstructor() { 279 | return (GetAccessFlags() & kAccConstructor) != 0; 280 | } 281 | 282 | // Returns true if the method is a class initializer. 283 | bool IsClassInitializer() { 284 | return IsConstructor() && IsStatic(); 285 | } 286 | 287 | // Returns true if the method is static, private, or a constructor. 288 | bool IsDirect() { 289 | return IsDirect(GetAccessFlags()); 290 | } 291 | 292 | static bool IsDirect(uint32_t access_flags) { 293 | constexpr uint32_t direct = kAccStatic | kAccPrivate | kAccConstructor; 294 | return (access_flags & direct) != 0; 295 | } 296 | 297 | // Returns true if the method is declared synchronized. 298 | bool IsSynchronized() { 299 | constexpr uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized; 300 | return (GetAccessFlags() & synchonized) != 0; 301 | } 302 | 303 | bool IsFinal() { 304 | return (GetAccessFlags() & kAccFinal) != 0; 305 | } 306 | 307 | bool IsCopied() { 308 | const bool copied = (GetAccessFlags() & kAccCopied) != 0; 309 | // (IsMiranda() || IsDefaultConflicting()) implies copied 310 | DCHECK(!(IsMiranda() || IsDefaultConflicting()) || copied) 311 | << "Miranda or default-conflict methods must always be copied."; 312 | return copied; 313 | } 314 | 315 | bool IsMiranda() { 316 | return (GetAccessFlags() & kAccMiranda) != 0; 317 | } 318 | 319 | // Returns true if invoking this method will not throw an AbstractMethodError or 320 | // IncompatibleClassChangeError. 321 | bool IsInvokable() { 322 | return !IsAbstract() && !IsDefaultConflicting(); 323 | } 324 | 325 | bool IsCompilable() { 326 | return (GetAccessFlags() & kAccCompileDontBother) == 0; 327 | } 328 | 329 | // A default conflict method is a special sentinel method that stands for a conflict between 330 | // multiple default methods. It cannot be invoked, throwing an IncompatibleClassChangeError if one 331 | // attempts to do so. 332 | bool IsDefaultConflicting() { 333 | return (GetAccessFlags() & kAccDefaultConflict) != 0u; 334 | } 335 | 336 | // This is set by the class linker. 337 | bool IsDefault() { 338 | return (GetAccessFlags() & kAccDefault) != 0; 339 | } 340 | 341 | template 342 | bool IsNative() { 343 | return (GetAccessFlags() & kAccNative) != 0; 344 | } 345 | 346 | bool IsFastNative() { 347 | constexpr uint32_t mask = kAccFastNative | kAccNative; 348 | return (GetAccessFlags() & mask) == mask; 349 | } 350 | 351 | bool IsAbstract() { 352 | return (GetAccessFlags() & kAccAbstract) != 0; 353 | } 354 | 355 | bool IsSynthetic() { 356 | return (GetAccessFlags() & kAccSynthetic) != 0; 357 | } 358 | 359 | bool IsProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_); 360 | 361 | bool SkipAccessChecks() { 362 | return (GetAccessFlags() & kAccSkipAccessChecks) != 0; 363 | } 364 | 365 | void SetSkipAccessChecks() { 366 | DCHECK(!SkipAccessChecks()); 367 | SetAccessFlags(GetAccessFlags() | kAccSkipAccessChecks); 368 | } 369 | 370 | // Should this method be run in the interpreter and count locks (e.g., failed structured- 371 | // locking verification)? 372 | bool MustCountLocks() { 373 | return (GetAccessFlags() & kAccMustCountLocks) != 0; 374 | } 375 | 376 | // Returns true if this method could be overridden by a default method. 377 | bool IsOverridableByDefaultMethod() SHARED_REQUIRES(Locks::mutator_lock_); 378 | 379 | bool CheckIncompatibleClassChange(InvokeType type) SHARED_REQUIRES(Locks::mutator_lock_); 380 | 381 | // Throws the error that would result from trying to invoke this method (i.e. 382 | // IncompatibleClassChangeError or AbstractMethodError). Only call if !IsInvokable(); 383 | void ThrowInvocationTimeError() SHARED_REQUIRES(Locks::mutator_lock_); 384 | 385 | uint16_t GetMethodIndex() SHARED_REQUIRES(Locks::mutator_lock_); 386 | 387 | // Doesn't do erroneous / unresolved class checks. 388 | uint16_t GetMethodIndexDuringLinking() SHARED_REQUIRES(Locks::mutator_lock_); 389 | 390 | size_t GetVtableIndex() SHARED_REQUIRES(Locks::mutator_lock_) { 391 | return GetMethodIndex(); 392 | } 393 | 394 | void SetMethodIndex(uint16_t new_method_index) SHARED_REQUIRES(Locks::mutator_lock_) { 395 | // Not called within a transaction. 396 | method_index_ = new_method_index; 397 | } 398 | 399 | /* AUPK Begin */ 400 | uint32_t get_method_idx(){ return dex_method_index_; } 401 | /* AUPK End */ 402 | 403 | static MemberOffset DexMethodIndexOffset() { 404 | return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_); 405 | } 406 | 407 | static MemberOffset MethodIndexOffset() { 408 | return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_); 409 | } 410 | 411 | uint32_t GetCodeItemOffset() { 412 | return dex_code_item_offset_; 413 | } 414 | 415 | void SetCodeItemOffset(uint32_t new_code_off) { 416 | // Not called within a transaction. 417 | dex_code_item_offset_ = new_code_off; 418 | } 419 | 420 | // Number of 32bit registers that would be required to hold all the arguments 421 | static size_t NumArgRegisters(const StringPiece& shorty); 422 | 423 | ALWAYS_INLINE uint32_t GetDexMethodIndex() SHARED_REQUIRES(Locks::mutator_lock_); 424 | 425 | void SetDexMethodIndex(uint32_t new_idx) { 426 | // Not called within a transaction. 427 | dex_method_index_ = new_idx; 428 | } 429 | 430 | ALWAYS_INLINE ArtMethod** GetDexCacheResolvedMethods(size_t pointer_size) 431 | SHARED_REQUIRES(Locks::mutator_lock_); 432 | ALWAYS_INLINE ArtMethod* GetDexCacheResolvedMethod(uint16_t method_index, size_t ptr_size) 433 | SHARED_REQUIRES(Locks::mutator_lock_); 434 | ALWAYS_INLINE void SetDexCacheResolvedMethod(uint16_t method_index, 435 | ArtMethod* new_method, 436 | size_t ptr_size) 437 | SHARED_REQUIRES(Locks::mutator_lock_); 438 | ALWAYS_INLINE void SetDexCacheResolvedMethods(ArtMethod** new_dex_cache_methods, size_t ptr_size) 439 | SHARED_REQUIRES(Locks::mutator_lock_); 440 | bool HasDexCacheResolvedMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); 441 | bool HasSameDexCacheResolvedMethods(ArtMethod* other, size_t pointer_size) 442 | SHARED_REQUIRES(Locks::mutator_lock_); 443 | bool HasSameDexCacheResolvedMethods(ArtMethod** other_cache, size_t pointer_size) 444 | SHARED_REQUIRES(Locks::mutator_lock_); 445 | 446 | template 447 | mirror::Class* GetDexCacheResolvedType(uint32_t type_idx, size_t ptr_size) 448 | SHARED_REQUIRES(Locks::mutator_lock_); 449 | void SetDexCacheResolvedTypes(GcRoot* new_dex_cache_types, size_t ptr_size) 450 | SHARED_REQUIRES(Locks::mutator_lock_); 451 | bool HasDexCacheResolvedTypes(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); 452 | bool HasSameDexCacheResolvedTypes(ArtMethod* other, size_t pointer_size) 453 | SHARED_REQUIRES(Locks::mutator_lock_); 454 | bool HasSameDexCacheResolvedTypes(GcRoot* other_cache, size_t pointer_size) 455 | SHARED_REQUIRES(Locks::mutator_lock_); 456 | 457 | // Get the Class* from the type index into this method's dex cache. 458 | mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve, size_t ptr_size) 459 | SHARED_REQUIRES(Locks::mutator_lock_); 460 | 461 | // Returns true if this method has the same name and signature of the other method. 462 | bool HasSameNameAndSignature(ArtMethod* other) SHARED_REQUIRES(Locks::mutator_lock_); 463 | 464 | // Find the method that this method overrides. 465 | ArtMethod* FindOverriddenMethod(size_t pointer_size) 466 | SHARED_REQUIRES(Locks::mutator_lock_); 467 | 468 | // Find the method index for this method within other_dexfile. If this method isn't present then 469 | // return DexFile::kDexNoIndex. The name_and_signature_idx MUST refer to a MethodId with the same 470 | // name and signature in the other_dexfile, such as the method index used to resolve this method 471 | // in the other_dexfile. 472 | uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile, 473 | uint32_t name_and_signature_idx) 474 | SHARED_REQUIRES(Locks::mutator_lock_); 475 | 476 | void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty) 477 | SHARED_REQUIRES(Locks::mutator_lock_); 478 | 479 | const void* GetEntryPointFromQuickCompiledCode() { 480 | return GetEntryPointFromQuickCompiledCodePtrSize(sizeof(void*)); 481 | } 482 | ALWAYS_INLINE const void* GetEntryPointFromQuickCompiledCodePtrSize(size_t pointer_size) { 483 | return GetNativePointer( 484 | EntryPointFromQuickCompiledCodeOffset(pointer_size), pointer_size); 485 | } 486 | 487 | void SetEntryPointFromQuickCompiledCode(const void* entry_point_from_quick_compiled_code) { 488 | SetEntryPointFromQuickCompiledCodePtrSize(entry_point_from_quick_compiled_code, 489 | sizeof(void*)); 490 | } 491 | ALWAYS_INLINE void SetEntryPointFromQuickCompiledCodePtrSize( 492 | const void* entry_point_from_quick_compiled_code, size_t pointer_size) { 493 | SetNativePointer(EntryPointFromQuickCompiledCodeOffset(pointer_size), 494 | entry_point_from_quick_compiled_code, pointer_size); 495 | } 496 | 497 | void RegisterNative(const void* native_method, bool is_fast) 498 | SHARED_REQUIRES(Locks::mutator_lock_); 499 | 500 | void UnregisterNative() SHARED_REQUIRES(Locks::mutator_lock_); 501 | 502 | static MemberOffset DexCacheResolvedMethodsOffset(size_t pointer_size) { 503 | return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER( 504 | PtrSizedFields, dex_cache_resolved_methods_) / sizeof(void*) * pointer_size); 505 | } 506 | 507 | static MemberOffset DexCacheResolvedTypesOffset(size_t pointer_size) { 508 | return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER( 509 | PtrSizedFields, dex_cache_resolved_types_) / sizeof(void*) * pointer_size); 510 | } 511 | 512 | static MemberOffset EntryPointFromJniOffset(size_t pointer_size) { 513 | return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER( 514 | PtrSizedFields, entry_point_from_jni_) / sizeof(void*) * pointer_size); 515 | } 516 | 517 | static MemberOffset EntryPointFromQuickCompiledCodeOffset(size_t pointer_size) { 518 | return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER( 519 | PtrSizedFields, entry_point_from_quick_compiled_code_) / sizeof(void*) * pointer_size); 520 | } 521 | 522 | ProfilingInfo* GetProfilingInfo(size_t pointer_size) { 523 | return reinterpret_cast(GetEntryPointFromJniPtrSize(pointer_size)); 524 | } 525 | 526 | ImtConflictTable* GetImtConflictTable(size_t pointer_size) { 527 | DCHECK(IsRuntimeMethod()); 528 | return reinterpret_cast(GetEntryPointFromJniPtrSize(pointer_size)); 529 | } 530 | 531 | ALWAYS_INLINE void SetImtConflictTable(ImtConflictTable* table, size_t pointer_size) { 532 | SetEntryPointFromJniPtrSize(table, pointer_size); 533 | } 534 | 535 | ALWAYS_INLINE void SetProfilingInfo(ProfilingInfo* info) { 536 | SetEntryPointFromJniPtrSize(info, sizeof(void*)); 537 | } 538 | 539 | ALWAYS_INLINE void SetProfilingInfoPtrSize(ProfilingInfo* info, size_t pointer_size) { 540 | SetEntryPointFromJniPtrSize(info, pointer_size); 541 | } 542 | 543 | static MemberOffset ProfilingInfoOffset() { 544 | return EntryPointFromJniOffset(sizeof(void*)); 545 | } 546 | 547 | void* GetEntryPointFromJni() { 548 | return GetEntryPointFromJniPtrSize(sizeof(void*)); 549 | } 550 | 551 | ALWAYS_INLINE void* GetEntryPointFromJniPtrSize(size_t pointer_size) { 552 | return GetNativePointer(EntryPointFromJniOffset(pointer_size), pointer_size); 553 | } 554 | 555 | void SetEntryPointFromJni(const void* entrypoint) { 556 | DCHECK(IsNative()); 557 | SetEntryPointFromJniPtrSize(entrypoint, sizeof(void*)); 558 | } 559 | 560 | ALWAYS_INLINE void SetEntryPointFromJniPtrSize(const void* entrypoint, size_t pointer_size) { 561 | SetNativePointer(EntryPointFromJniOffset(pointer_size), entrypoint, pointer_size); 562 | } 563 | 564 | // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal 565 | // conventions for a method of managed code. Returns false for Proxy methods. 566 | ALWAYS_INLINE bool IsRuntimeMethod(); 567 | 568 | // Is this a hand crafted method used for something like describing callee saves? 569 | bool IsCalleeSaveMethod() SHARED_REQUIRES(Locks::mutator_lock_); 570 | 571 | bool IsResolutionMethod() SHARED_REQUIRES(Locks::mutator_lock_); 572 | 573 | bool IsImtUnimplementedMethod() SHARED_REQUIRES(Locks::mutator_lock_); 574 | 575 | MethodReference ToMethodReference() SHARED_REQUIRES(Locks::mutator_lock_) { 576 | return MethodReference(GetDexFile(), GetDexMethodIndex()); 577 | } 578 | 579 | // Find the catch block for the given exception type and dex_pc. When a catch block is found, 580 | // indicates whether the found catch block is responsible for clearing the exception or whether 581 | // a move-exception instruction is present. 582 | uint32_t FindCatchBlock(Handle exception_type, uint32_t dex_pc, 583 | bool* has_no_move_exception) 584 | SHARED_REQUIRES(Locks::mutator_lock_); 585 | 586 | // NO_THREAD_SAFETY_ANALYSIS since we don't know what the callback requires. 587 | template 588 | void VisitRoots(RootVisitorType& visitor, size_t pointer_size) NO_THREAD_SAFETY_ANALYSIS; 589 | 590 | const DexFile* GetDexFile() SHARED_REQUIRES(Locks::mutator_lock_); 591 | 592 | const char* GetDeclaringClassDescriptor() SHARED_REQUIRES(Locks::mutator_lock_); 593 | 594 | const char* GetShorty() SHARED_REQUIRES(Locks::mutator_lock_) { 595 | uint32_t unused_length; 596 | return GetShorty(&unused_length); 597 | } 598 | 599 | const char* GetShorty(uint32_t* out_length) SHARED_REQUIRES(Locks::mutator_lock_); 600 | 601 | const Signature GetSignature() SHARED_REQUIRES(Locks::mutator_lock_); 602 | 603 | ALWAYS_INLINE const char* GetName() SHARED_REQUIRES(Locks::mutator_lock_); 604 | 605 | mirror::String* GetNameAsString(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_); 606 | 607 | const DexFile::CodeItem* GetCodeItem() SHARED_REQUIRES(Locks::mutator_lock_); 608 | 609 | bool IsResolvedTypeIdx(uint16_t type_idx, size_t ptr_size) SHARED_REQUIRES(Locks::mutator_lock_); 610 | 611 | int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_REQUIRES(Locks::mutator_lock_); 612 | 613 | const DexFile::ProtoId& GetPrototype() SHARED_REQUIRES(Locks::mutator_lock_); 614 | 615 | const DexFile::TypeList* GetParameterTypeList() SHARED_REQUIRES(Locks::mutator_lock_); 616 | 617 | const char* GetDeclaringClassSourceFile() SHARED_REQUIRES(Locks::mutator_lock_); 618 | 619 | uint16_t GetClassDefIndex() SHARED_REQUIRES(Locks::mutator_lock_); 620 | 621 | const DexFile::ClassDef& GetClassDef() SHARED_REQUIRES(Locks::mutator_lock_); 622 | 623 | const char* GetReturnTypeDescriptor() SHARED_REQUIRES(Locks::mutator_lock_); 624 | 625 | const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx) 626 | SHARED_REQUIRES(Locks::mutator_lock_); 627 | 628 | // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large 629 | // number of bugs at call sites. 630 | mirror::Class* GetReturnType(bool resolve, size_t ptr_size) 631 | SHARED_REQUIRES(Locks::mutator_lock_); 632 | 633 | mirror::ClassLoader* GetClassLoader() SHARED_REQUIRES(Locks::mutator_lock_); 634 | 635 | mirror::DexCache* GetDexCache() SHARED_REQUIRES(Locks::mutator_lock_); 636 | 637 | ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy(size_t pointer_size) 638 | SHARED_REQUIRES(Locks::mutator_lock_); 639 | 640 | // May cause thread suspension due to class resolution. 641 | bool EqualParameters(Handle> params) 642 | SHARED_REQUIRES(Locks::mutator_lock_); 643 | 644 | // Size of an instance of this native class. 645 | static size_t Size(size_t pointer_size) { 646 | return RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size) + 647 | (sizeof(PtrSizedFields) / sizeof(void*)) * pointer_size; 648 | } 649 | 650 | // Alignment of an instance of this native class. 651 | static size_t Alignment(size_t pointer_size) { 652 | // The ArtMethod alignment is the same as image pointer size. This differs from 653 | // alignof(ArtMethod) if cross-compiling with pointer_size != sizeof(void*). 654 | return pointer_size; 655 | } 656 | 657 | void CopyFrom(ArtMethod* src, size_t image_pointer_size) 658 | SHARED_REQUIRES(Locks::mutator_lock_); 659 | 660 | ALWAYS_INLINE GcRoot* GetDexCacheResolvedTypes(size_t pointer_size) 661 | SHARED_REQUIRES(Locks::mutator_lock_); 662 | 663 | // Note, hotness_counter_ updates are non-atomic but it doesn't need to be precise. Also, 664 | // given that the counter is only 16 bits wide we can expect wrap-around in some 665 | // situations. Consumers of hotness_count_ must be able to deal with that. 666 | uint16_t IncrementCounter() { 667 | return ++hotness_count_; 668 | } 669 | 670 | void ClearCounter() { 671 | hotness_count_ = 0; 672 | } 673 | 674 | void SetCounter(int16_t hotness_count) { 675 | hotness_count_ = hotness_count; 676 | } 677 | 678 | uint16_t GetCounter() const { 679 | return hotness_count_; 680 | } 681 | 682 | const uint8_t* GetQuickenedInfo() SHARED_REQUIRES(Locks::mutator_lock_); 683 | 684 | // Returns the method header for the compiled code containing 'pc'. Note that runtime 685 | // methods will return null for this method, as they are not oat based. 686 | const OatQuickMethodHeader* GetOatQuickMethodHeader(uintptr_t pc) 687 | SHARED_REQUIRES(Locks::mutator_lock_); 688 | 689 | // Returns whether the method has any compiled code, JIT or AOT. 690 | bool HasAnyCompiledCode() SHARED_REQUIRES(Locks::mutator_lock_); 691 | 692 | 693 | // Update heap objects and non-entrypoint pointers by the passed in visitor for image relocation. 694 | // Does not use read barrier. 695 | template 696 | ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor, size_t pointer_size) 697 | SHARED_REQUIRES(Locks::mutator_lock_); 698 | 699 | // Update entry points by passing them through the visitor. 700 | template 701 | ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor, size_t pointer_size); 702 | 703 | protected: 704 | // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". 705 | // The class we are a part of. 706 | GcRoot declaring_class_; 707 | 708 | // Access flags; low 16 bits are defined by spec. 709 | uint32_t access_flags_; 710 | 711 | /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */ 712 | 713 | // Offset to the CodeItem. 714 | uint32_t dex_code_item_offset_; 715 | 716 | // Index into method_ids of the dex file associated with this method. 717 | uint32_t dex_method_index_; 718 | 719 | /* End of dex file fields. */ 720 | 721 | // Entry within a dispatch table for this method. For static/direct methods the index is into 722 | // the declaringClass.directMethods, for virtual methods the vtable and for interface methods the 723 | // ifTable. 724 | uint16_t method_index_; 725 | 726 | // The hotness we measure for this method. Managed by the interpreter. Not atomic, as we allow 727 | // missing increments: if the method is hot, we will see it eventually. 728 | uint16_t hotness_count_; 729 | 730 | // Fake padding field gets inserted here. 731 | 732 | // Must be the last fields in the method. 733 | // PACKED(4) is necessary for the correctness of 734 | // RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size). 735 | struct PACKED(4) PtrSizedFields { 736 | // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. 737 | ArtMethod** dex_cache_resolved_methods_; 738 | 739 | // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access. 740 | GcRoot* dex_cache_resolved_types_; 741 | 742 | // Pointer to JNI function registered to this method, or a function to resolve the JNI function, 743 | // or the profiling data for non-native methods, or an ImtConflictTable. 744 | void* entry_point_from_jni_; 745 | 746 | // Method dispatch from quick compiled code invokes this pointer which may cause bridging into 747 | // the interpreter. 748 | void* entry_point_from_quick_compiled_code_; 749 | } ptr_sized_fields_; 750 | 751 | private: 752 | static size_t PtrSizedFieldsOffset(size_t pointer_size) { 753 | // Round up to pointer size for padding field. 754 | return RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size); 755 | } 756 | 757 | template 758 | ALWAYS_INLINE T GetNativePointer(MemberOffset offset, size_t pointer_size) const { 759 | static_assert(std::is_pointer::value, "T must be a pointer type"); 760 | DCHECK(ValidPointerSize(pointer_size)) << pointer_size; 761 | const auto addr = reinterpret_cast(this) + offset.Uint32Value(); 762 | if (pointer_size == sizeof(uint32_t)) { 763 | return reinterpret_cast(*reinterpret_cast(addr)); 764 | } else { 765 | auto v = *reinterpret_cast(addr); 766 | return reinterpret_cast(dchecked_integral_cast(v)); 767 | } 768 | } 769 | 770 | template 771 | ALWAYS_INLINE void SetNativePointer(MemberOffset offset, T new_value, size_t pointer_size) { 772 | static_assert(std::is_pointer::value, "T must be a pointer type"); 773 | DCHECK(ValidPointerSize(pointer_size)) << pointer_size; 774 | const auto addr = reinterpret_cast(this) + offset.Uint32Value(); 775 | if (pointer_size == sizeof(uint32_t)) { 776 | uintptr_t ptr = reinterpret_cast(new_value); 777 | *reinterpret_cast(addr) = dchecked_integral_cast(ptr); 778 | } else { 779 | *reinterpret_cast(addr) = reinterpret_cast(new_value); 780 | } 781 | } 782 | 783 | DISALLOW_COPY_AND_ASSIGN(ArtMethod); // Need to use CopyFrom to deal with 32 vs 64 bits. 784 | }; 785 | 786 | } // namespace art 787 | 788 | #endif // ART_RUNTIME_ART_METHOD_H_ 789 | -------------------------------------------------------------------------------- /art/runtime/aupk.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "aupk.h" 3 | #include 4 | #include "runtime.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "arch/context.h" 23 | #include "art_field-inl.h" 24 | #include "art_method-inl.h" 25 | #include "base/stringpiece.h" 26 | #include "class_linker-inl.h" 27 | #include "debugger.h" 28 | #include "dex_instruction.h" 29 | #include "entrypoints/runtime_asm_entrypoints.h" 30 | #include "gc/accounting/card_table-inl.h" 31 | #include "interpreter/interpreter.h" 32 | #include "jit/jit.h" 33 | #include "jit/jit_code_cache.h" 34 | #include "jit/profiling_info.h" 35 | #include "jni_internal.h" 36 | #include "mirror/abstract_method.h" 37 | #include "mirror/class-inl.h" 38 | #include "mirror/object_array-inl.h" 39 | #include "mirror/object-inl.h" 40 | #include "mirror/string.h" 41 | #include "oat_file-inl.h" 42 | #include "scoped_thread_state_change.h" 43 | #include "well_known_classes.h" 44 | #include "json.hpp" 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include "reflection.h" 50 | //#include "scoped_fast_native_object_access.h" 51 | 52 | using json = nlohmann::json; 53 | using namespace std; 54 | 55 | namespace art 56 | { 57 | extern "C" ArtMethod *jMethodToArtMethod(JNIEnv *env, jobject jMethod); 58 | map methodMap; 59 | list dexFiles; 60 | 61 | Thread *Aupk::aupkThread = nullptr; 62 | ArtMethod *Aupk::aupkArtMethod = nullptr; 63 | 64 | /** 65 | * 供 dalvik_system_DexFile.cc->DexFile_fakeInvoke调用 66 | * 构造主动调用的参数,并进行调用 67 | */ 68 | void Aupk::aupkFakeInvoke(ArtMethod *artMethod) SHARED_REQUIRES(Locks::mutator_lock_) 69 | { 70 | if (artMethod->IsAbstract() || artMethod->IsNative() || (!artMethod->IsInvokable()) || artMethod->IsProxyMethod()) 71 | { 72 | return; 73 | } 74 | JValue result; 75 | Thread *self = Thread::Current(); 76 | uint32_t args_size = (uint32_t)ArtMethod::NumArgRegisters(artMethod->GetShorty()); 77 | 78 | if (!artMethod->IsStatic()) 79 | { 80 | args_size += 1; 81 | } 82 | std::vector args(args_size, 0); 83 | if (!artMethod->IsStatic()) 84 | { 85 | // 第一个参数赋值为除0以外的任何值,因为后面会判断 arg[0]==nullptr 86 | args[0] = 0x12345678; 87 | } 88 | artMethod->Invoke(self, args.data(), args_size, &result, artMethod->GetShorty()); 89 | } 90 | 91 | uint8_t *Aupk::getCodeItemEnd(const uint8_t **pData) 92 | { 93 | uint32_t num_of_list = DecodeUnsignedLeb128(pData); 94 | for (; num_of_list > 0; num_of_list--) 95 | { 96 | int32_t num_of_handlers = 97 | DecodeSignedLeb128(pData); 98 | int num = num_of_handlers; 99 | if (num_of_handlers <= 0) 100 | { 101 | num = -num_of_handlers; 102 | } 103 | for (; num > 0; num--) 104 | { 105 | DecodeUnsignedLeb128(pData); 106 | DecodeUnsignedLeb128(pData); 107 | } 108 | if (num_of_handlers <= 0) 109 | { 110 | DecodeUnsignedLeb128(pData); 111 | } 112 | } 113 | return (uint8_t *)(*pData); 114 | } 115 | 116 | /** 117 | * base64编码 118 | */ 119 | char *Aupk::base64Encode(char *str, long str_len, long *outlen) 120 | { 121 | long len; 122 | char *res; 123 | int i, j; 124 | const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 125 | if (str_len % 3 == 0) 126 | len = str_len / 3 * 4; 127 | else 128 | len = (str_len / 3 + 1) * 4; 129 | 130 | res = (char *)malloc(sizeof(char) * (len + 1)); 131 | res[len] = '\0'; 132 | *outlen = len; 133 | for (i = 0, j = 0; i < len - 2; j += 3, i += 4) 134 | { 135 | res[i] = base64_table[str[j] >> 2]; 136 | res[i + 1] = 137 | base64_table[(str[j] & 0x3) << 4 | 138 | (str[j + 1] >> 4)]; 139 | res[i + 2] = 140 | base64_table[(str[j + 1] & 0xf) << 2 | 141 | (str[j + 2] >> 6)]; 142 | res[i + 3] = base64_table[str[j + 2] & 0x3f]; 143 | } 144 | 145 | switch (str_len % 3) 146 | { 147 | case 1: 148 | res[i - 2] = '='; 149 | res[i - 1] = '='; 150 | break; 151 | case 2: 152 | res[i - 1] = '='; 153 | break; 154 | } 155 | 156 | return res; 157 | } 158 | 159 | /** 160 | * 获取当前进程名 161 | */ 162 | bool Aupk::getProcessName(char *szProcName) 163 | { 164 | int fcmdline = -1; 165 | char szCmdline[64] = {0}; 166 | int procid = getpid(); 167 | sprintf(szCmdline, "/proc/%d/cmdline", procid); 168 | fcmdline = open(szCmdline, O_RDONLY, 0644); 169 | bool result = true; 170 | if (fcmdline > 0) 171 | { 172 | if (read(fcmdline, szProcName, 256) <= 0) 173 | { 174 | LOG(INFO) << "AUPK->art_method.cc:getProcessName,read process name failed:" << strerror(errno); 175 | result = false; 176 | } 177 | } 178 | if (!szProcName[0]) 179 | { 180 | LOG(INFO) << "AUPK->art_method.cc:getProcessName,process name is null:" << strerror(errno); 181 | result = false; 182 | } 183 | close(fcmdline); 184 | return result; 185 | } 186 | 187 | /** 188 | * 将MethodInfo信息从内存映射到文件 189 | */ 190 | void Aupk::mapToFile() 191 | { 192 | LOG(INFO) << "AUPK->method list file count:" << methodMap.size(); 193 | for (map::iterator iter = methodMap.begin(); iter != methodMap.end(); iter++) 194 | { 195 | fstream file; 196 | const char *fileName = iter->first.c_str(); 197 | string methodInfo = iter->second; 198 | 199 | // 删除结尾的逗号,并完善成json格式 200 | methodInfo.erase(methodInfo.size() - 1); 201 | methodInfo += "]}"; 202 | 203 | // 如果文件已存在,那么删除它 204 | file.open(fileName, ios::in); 205 | if (file.is_open()) 206 | { 207 | remove(fileName); 208 | LOG(INFO) << "AUPK->remove fileName:" << fileName; 209 | } 210 | file.close(); 211 | 212 | // 保存到文件 213 | file.open(fileName, ios::out); 214 | file << methodInfo; 215 | file.close(); 216 | LOG(INFO) << "AUPK->dump method information success:" << fileName; 217 | } 218 | methodMap.clear(); 219 | } 220 | 221 | /** 222 | * dump Dex文件里的所有类名 223 | */ 224 | void Aupk::dumpClassName(const DexFile *dexFile, const char *feature) 225 | { 226 | char szProcName[256] = {0}; 227 | if (!getProcessName(szProcName)) 228 | { 229 | LOG(INFO) << "AUPK->dumpMethod:" 230 | << "get process name failed"; 231 | return; 232 | } 233 | // 创建目录 234 | char filePath[256] = {0}; 235 | sprintf(filePath, "/data/data/%s/aupk", szProcName); 236 | mkdir(filePath, 0777); 237 | 238 | // 构造文件名 239 | char fileName[256] = {0}; 240 | int dexFileSize = (int)dexFile->Size(); 241 | sprintf(fileName, "%s/%d_%s_class.json", filePath, dexFileSize, feature); 242 | 243 | ifstream iFile; 244 | iFile.open(fileName, ios::in); 245 | if (!iFile.is_open()) 246 | { 247 | // 创建文件 248 | json root; 249 | for (size_t i = 0; i < dexFile->NumClassDefs(); i++) 250 | { 251 | const DexFile::ClassDef &classDef = dexFile->GetClassDef(i); 252 | const char *descriptor = dexFile->GetClassDescriptor(classDef); 253 | root["count"] = i + 1; 254 | root["data"][i] = descriptor; 255 | } 256 | ofstream oFile; 257 | oFile.open(fileName, ios::out); 258 | if (oFile.is_open()) 259 | { 260 | oFile << root; 261 | oFile.close(); 262 | LOG(INFO) << "AUPK->dump class name:success:" << fileName; 263 | } 264 | else 265 | { 266 | //LOG(INFO) << "AUPK->dumpClassName:failed,file name:" << fileName << ",error:" << strerror(errno); 267 | } 268 | } 269 | else 270 | { 271 | // 文件已存在 272 | //LOG(INFO) << "AUPK->dumpClassName:file exist"; 273 | iFile.close(); 274 | } 275 | } 276 | 277 | /** 278 | * 获取并储存method的信息 279 | */ 280 | void Aupk::dumpMethod(ArtMethod *artMethod, const char *feature) SHARED_REQUIRES(Locks::mutator_lock_) 281 | { 282 | char *szProcName = (char *)malloc(256); 283 | memset(szProcName, 0, 256); 284 | if (!getProcessName(szProcName)) 285 | { 286 | LOG(INFO) << "AUPK->dumpMethod:" 287 | << "get process name failed"; 288 | return; 289 | } 290 | 291 | const DexFile *dexFile = artMethod->GetDexFile(); 292 | string methodName = PrettyMethod(artMethod); 293 | 294 | //LOG(INFO) << "AUPK->dumpMethod:"<Begin(); 297 | 298 | int dexFileSize = (int)dexFile->Size(); 299 | uint32_t methodIndex = artMethod->get_method_idx(); 300 | const DexFile::CodeItem *codeItem = artMethod->GetCodeItem(); 301 | if (codeItem == nullptr) 302 | { 303 | //LOG(ERROR) << "AUPK->dumpMethod:"<< "codeItem is null"; 304 | return; 305 | } 306 | 307 | // 创建目录 308 | char *filePath = (char *)malloc(256); 309 | memset(filePath, 0, 256); 310 | sprintf(filePath, "/data/data/%s/aupk", szProcName); 311 | mkdir(filePath, 0777); 312 | 313 | // 构造文件名 314 | char *fileName = (char *)malloc(256); 315 | memset(fileName, 0, 256); 316 | sprintf(fileName, "%s/%d_%s_method.json", filePath, dexFileSize, feature); 317 | 318 | // 计算codeItem的长度 319 | int codeItemLength = 0; 320 | uint8_t *item = (uint8_t *)codeItem; 321 | if (codeItem->tries_size_ > 0) 322 | { 323 | const uint8_t *handlerData = (const uint8_t *)(DexFile::GetTryItems(*codeItem, codeItem->tries_size_)); 324 | uint8_t *tail = getCodeItemEnd(&handlerData); 325 | codeItemLength = (int)(tail - item); 326 | } 327 | else 328 | { 329 | codeItemLength = 16 + codeItem->insns_size_in_code_units_ * 2; 330 | } 331 | 332 | int offset = (int)(item - dexFileBegin); 333 | long outlen = 0; 334 | char *base64Code = base64Encode((char *)item, (long)codeItemLength, &outlen); 335 | 336 | string *methodInfo = nullptr; 337 | bool isNeedDelete = false; 338 | if (methodMap.count(fileName)) 339 | { 340 | // the method list entry exist 341 | methodInfo = &(methodMap.find(fileName)->second); 342 | } 343 | else 344 | { 345 | methodInfo = new string(); 346 | isNeedDelete = true; 347 | (*methodInfo) += "{\"count\":0,\"data\":["; 348 | } 349 | 350 | // count++ 351 | stringstream sstream; 352 | int count = 0; 353 | int pos1 = methodInfo->find("\"count\":"); 354 | int pos2 = methodInfo->find(",\"data\":"); 355 | if (pos1 != -1 && pos2 != -1) 356 | { 357 | string strCount = methodInfo->substr(pos1 + 8, pos2 - (pos1 + 8)); 358 | sstream << strCount; 359 | sstream >> count; 360 | sstream.clear(); 361 | } 362 | count++; 363 | sstream << count; 364 | string strCount; 365 | sstream >> strCount; 366 | sstream.clear(); 367 | methodInfo->replace(pos1 + 8, pos2 - (pos1 + 8), strCount); 368 | 369 | // convert index,offset,codeLen to string 370 | string strMethodIndex; 371 | sstream << methodIndex; 372 | sstream >> strMethodIndex; 373 | if (strMethodIndex.empty()) 374 | strMethodIndex = "0"; 375 | sstream.clear(); 376 | 377 | string strOffset; 378 | sstream << offset; 379 | sstream >> strOffset; 380 | if (strOffset.empty()) 381 | strOffset = "0"; 382 | sstream.clear(); 383 | 384 | string strCodeItemLength; 385 | sstream << codeItemLength; 386 | sstream >> strCodeItemLength; 387 | if (strCodeItemLength.empty()) 388 | strCodeItemLength = "0"; 389 | sstream.clear(); 390 | 391 | /** 392 | * add method information to list 393 | * 不知为何,在这里使用nlohmannjson来操作会发生错误,为了兼容dex修复程序,这里就直接拼接成json格式了 394 | * @name 函数名 395 | * @index 函数索引 396 | * @offset 函数偏移 397 | * @codeItemLength 函数codeItem长度 398 | * @inst 函数指令的base64串 399 | * 修复思路为:获取dex的每一个类里的每一个direct method 和virtual method,并获取其index,和codeOffset 400 | * 再从下列存储的信息里,找到对应index的method,并将其inst进行base64解码,然后填充回codeOffset 401 | */ 402 | *methodInfo += "{\"name\":" + string("\"") + methodName + string("\"") + string(","); 403 | *methodInfo += "\"index\":" + strMethodIndex + string(","); 404 | *methodInfo += "\"offset\":" + strOffset + string(","); 405 | *methodInfo += "\"codeItemLength\":" + strCodeItemLength + string(","); 406 | *methodInfo += "\"inst\":" + string("\"") + string(base64Code) + string("\""); 407 | *methodInfo += "},"; 408 | methodMap.insert(pair(string(fileName), *methodInfo)); 409 | 410 | free(szProcName); 411 | free(filePath); 412 | free(fileName); 413 | free(base64Code); 414 | if (isNeedDelete) 415 | { 416 | delete methodInfo; 417 | methodInfo = nullptr; 418 | } 419 | } 420 | 421 | /** 422 | * dump Dex文件 423 | */ 424 | void Aupk::dumpDexFile(const DexFile *dexFile, const char *feature) SHARED_REQUIRES(Locks::mutator_lock_) 425 | { 426 | char szProcName[256] = {0}; 427 | if (!getProcessName(szProcName)) 428 | { 429 | LOG(INFO) << "AUPK->dumpDexFile:" 430 | << "get process name failed"; 431 | return; 432 | } 433 | 434 | // make dir in the sdcard for aupk 435 | const uint8_t *dexFileBegin = dexFile->Begin(); 436 | int dexFileSize = (int)dexFile->Size(); 437 | 438 | // 创建目录 439 | char filePath[256] = {0}; 440 | sprintf(filePath, "/data/data/%s/aupk", szProcName); 441 | mkdir(filePath, 0777); 442 | 443 | // 构造文件名 444 | char fileName[256] = {0}; 445 | sprintf(fileName, "%s/%d_%s.dex", filePath, dexFileSize, feature); 446 | 447 | int dexFilefp = open(fileName, O_RDONLY, 0666); 448 | if (dexFilefp > 0) 449 | { 450 | // the dex file exist 451 | close(dexFilefp); 452 | dexFilefp = 0; 453 | return; 454 | } 455 | 456 | // dump the dex file 457 | dexFilefp = open(fileName, O_CREAT | O_RDWR, 0666); 458 | if (dexFilefp > 0) 459 | { 460 | if (write(dexFilefp, (void *)dexFileBegin, dexFileSize) <= 0) 461 | { 462 | LOG(INFO) << "AUPK->dumpDexFile,dex name:" << fileName << ";write dex file failed:" << strerror(errno); 463 | close(dexFilefp); 464 | return; 465 | } 466 | fsync(dexFilefp); 467 | close(dexFilefp); 468 | LOG(INFO) << "AUPK->dump dex file success:" << fileName; 469 | } 470 | } 471 | 472 | /** 473 | * 存储当前线程对象 474 | * 一般来讲,只有在主动调用线程里会调用这个函数 475 | */ 476 | void Aupk::setThread(Thread *thread) 477 | { 478 | aupkThread = thread; 479 | } 480 | 481 | /** 482 | * 存储artMethod 483 | * 在主动调用时,存储正在调用的method 484 | */ 485 | void Aupk::setMethod(ArtMethod *method) 486 | { 487 | aupkArtMethod = method; 488 | } 489 | 490 | /** 491 | * 判断方法是否为主动调用 492 | * 根据存储的 aupkThread 和 aupkArtMethod 来判断是否为主动调用的函数 493 | */ 494 | bool Aupk::isFakeInvoke(Thread *thread, ArtMethod *method) SHARED_REQUIRES(Locks::mutator_lock_) 495 | { 496 | if (aupkThread == nullptr || aupkArtMethod == nullptr || thread == nullptr || method == nullptr) 497 | { 498 | return false; 499 | } 500 | 501 | if ((thread->GetTid() == aupkThread->GetTid()) && 502 | strcmp(PrettyMethod(method).c_str(), PrettyMethod(aupkArtMethod).c_str()) == 0) 503 | { 504 | return true; 505 | } 506 | return false; 507 | } 508 | 509 | /** 510 | * Native函数 511 | * 将java方法转为ArtMethod对象,并进行主动调用 512 | */ 513 | static void Aupk_native_fakeInvoke(JNIEnv *env, jclass, jobject jMethod) SHARED_REQUIRES(Locks::mutator_lock_) 514 | { 515 | if (env) 516 | { 517 | } 518 | if (jMethod != nullptr) 519 | { 520 | Thread *self = Thread::Current(); 521 | ArtMethod *artMethod = jMethodToArtMethod(env, jMethod); 522 | Aupk::setThread(self); 523 | Aupk::setMethod(artMethod); 524 | Aupk::aupkFakeInvoke(artMethod); 525 | } 526 | return; 527 | } 528 | 529 | static void Aupk_mapToFile(JNIEnv *env, jclass) 530 | { 531 | if (env) 532 | { 533 | } 534 | Aupk::mapToFile(); 535 | } 536 | 537 | static JNINativeMethod gMethods[] = { 538 | NATIVE_METHOD(Aupk, native_fakeInvoke, "(Ljava/lang/Object;)V"), 539 | NATIVE_METHOD(Aupk, mapToFile, "()V"), 540 | }; 541 | 542 | // 注册native函数,须在runtime.cc中调用 543 | void Aupk::register_android_app_Aupk(JNIEnv *env) 544 | { 545 | REGISTER_NATIVE_METHODS("android/app/Aupk"); 546 | } 547 | 548 | } -------------------------------------------------------------------------------- /art/runtime/aupk.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ART_RUNTIME_AUPK_H_ 3 | #define ART_RUNTIME_AUPK_H_ 4 | 5 | #include "art_method.h" 6 | #include "thread.h" 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | 14 | 15 | namespace art 16 | { 17 | //void register_android_app_Aupk(JNIEnv *env); 18 | 19 | 20 | 21 | class Aupk 22 | { 23 | public: 24 | 25 | 26 | static void aupkFakeInvoke(ArtMethod *artMethod); 27 | 28 | static uint8_t *getCodeItemEnd(const uint8_t **pData); 29 | static char *base64Encode(char *str, long str_len, long *outlen); 30 | static bool getProcessName(char *szProcName); 31 | 32 | static void mapToFile(); 33 | static void dumpClassName(const DexFile *dexFile, const char *feature); 34 | static void dumpMethod(ArtMethod *artMethod, const char *feature); 35 | static void dumpDexFile(const DexFile *dexFile, const char *feature); 36 | 37 | static void setThread(Thread *thread); 38 | static void setMethod(ArtMethod *method); 39 | static bool isFakeInvoke(Thread *thread, ArtMethod *method); 40 | static void register_android_app_Aupk(JNIEnv *env); 41 | 42 | private: 43 | static Thread *aupkThread; 44 | static ArtMethod *aupkArtMethod; 45 | }; 46 | 47 | } 48 | 49 | #endif // ART_RUNTIME_AUPK_H_ 50 | -------------------------------------------------------------------------------- /art/runtime/interpreter/interpreter.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "interpreter.h" 18 | 19 | #include 20 | 21 | #include "common_throws.h" 22 | #include "interpreter_common.h" 23 | #include "mirror/string-inl.h" 24 | #include "scoped_thread_state_change.h" 25 | #include "ScopedLocalRef.h" 26 | #include "stack.h" 27 | #include "unstarted_runtime.h" 28 | #include "mterp/mterp.h" 29 | #include "jit/jit.h" 30 | #include "jit/jit_code_cache.h" 31 | 32 | /* AUPK Begin */ 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "art_method-inl.h" 38 | #include "mirror/class-inl.h" 39 | #include "mirror/object_array-inl.h" 40 | #include "reflection.h" 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include "aupk.h" 46 | /* AUPK End */ 47 | 48 | namespace art 49 | { 50 | namespace interpreter 51 | { 52 | 53 | static void InterpreterJni(Thread *self, ArtMethod *method, const StringPiece &shorty, 54 | Object *receiver, uint32_t *args, JValue *result) 55 | SHARED_REQUIRES(Locks::mutator_lock_) 56 | { 57 | // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler, 58 | // it should be removed and JNI compiled stubs used instead. 59 | LOG(INFO)<<"fakeInvoke shorty:"<IsStatic()) 62 | { 63 | if (shorty == "L") 64 | { 65 | typedef jobject(fntype)(JNIEnv *, jclass); 66 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 67 | ScopedLocalRef klass(soa.Env(), 68 | soa.AddLocalReference(method->GetDeclaringClass())); 69 | jobject jresult; 70 | { 71 | ScopedThreadStateChange tsc(self, kNative); 72 | jresult = fn(soa.Env(), klass.get()); 73 | } 74 | result->SetL(soa.Decode(jresult)); 75 | } 76 | else if (shorty == "V") 77 | { 78 | typedef void(fntype)(JNIEnv *, jclass); 79 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 80 | ScopedLocalRef klass(soa.Env(), 81 | soa.AddLocalReference(method->GetDeclaringClass())); 82 | ScopedThreadStateChange tsc(self, kNative); 83 | fn(soa.Env(), klass.get()); 84 | } 85 | else if (shorty == "Z") 86 | { 87 | typedef jboolean(fntype)(JNIEnv *, jclass); 88 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 89 | ScopedLocalRef klass(soa.Env(), 90 | soa.AddLocalReference(method->GetDeclaringClass())); 91 | ScopedThreadStateChange tsc(self, kNative); 92 | result->SetZ(fn(soa.Env(), klass.get())); 93 | } 94 | else if (shorty == "BI") 95 | { 96 | typedef jbyte(fntype)(JNIEnv *, jclass, jint); 97 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 98 | ScopedLocalRef klass(soa.Env(), 99 | soa.AddLocalReference(method->GetDeclaringClass())); 100 | ScopedThreadStateChange tsc(self, kNative); 101 | result->SetB(fn(soa.Env(), klass.get(), args[0])); 102 | } 103 | else if (shorty == "II") 104 | { 105 | typedef jint(fntype)(JNIEnv *, jclass, jint); 106 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 107 | ScopedLocalRef klass(soa.Env(), 108 | soa.AddLocalReference(method->GetDeclaringClass())); 109 | ScopedThreadStateChange tsc(self, kNative); 110 | result->SetI(fn(soa.Env(), klass.get(), args[0])); 111 | } 112 | else if (shorty == "LL") 113 | { 114 | typedef jobject(fntype)(JNIEnv *, jclass, jobject); 115 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 116 | ScopedLocalRef klass(soa.Env(), 117 | soa.AddLocalReference(method->GetDeclaringClass())); 118 | ScopedLocalRef arg0(soa.Env(), 119 | soa.AddLocalReference( 120 | reinterpret_cast(args[0]))); 121 | jobject jresult; 122 | { 123 | ScopedThreadStateChange tsc(self, kNative); 124 | jresult = fn(soa.Env(), klass.get(), arg0.get()); 125 | } 126 | result->SetL(soa.Decode(jresult)); 127 | } 128 | else if (shorty == "IIZ") 129 | { 130 | typedef jint(fntype)(JNIEnv *, jclass, jint, jboolean); 131 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 132 | ScopedLocalRef klass(soa.Env(), 133 | soa.AddLocalReference(method->GetDeclaringClass())); 134 | ScopedThreadStateChange tsc(self, kNative); 135 | result->SetI(fn(soa.Env(), klass.get(), args[0], args[1])); 136 | } 137 | else if (shorty == "ILI") 138 | { 139 | typedef jint(fntype)(JNIEnv *, jclass, jobject, jint); 140 | fntype *const fn = reinterpret_cast(const_cast( 141 | method->GetEntryPointFromJni())); 142 | ScopedLocalRef klass(soa.Env(), 143 | soa.AddLocalReference(method->GetDeclaringClass())); 144 | ScopedLocalRef arg0(soa.Env(), 145 | soa.AddLocalReference( 146 | reinterpret_cast(args[0]))); 147 | ScopedThreadStateChange tsc(self, kNative); 148 | result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1])); 149 | } 150 | else if (shorty == "SIZ") 151 | { 152 | typedef jshort(fntype)(JNIEnv *, jclass, jint, jboolean); 153 | fntype *const fn = 154 | reinterpret_cast(const_cast(method->GetEntryPointFromJni())); 155 | ScopedLocalRef klass(soa.Env(), 156 | soa.AddLocalReference(method->GetDeclaringClass())); 157 | ScopedThreadStateChange tsc(self, kNative); 158 | result->SetS(fn(soa.Env(), klass.get(), args[0], args[1])); 159 | } 160 | else if (shorty == "VIZ") 161 | { 162 | typedef void(fntype)(JNIEnv *, jclass, jint, jboolean); 163 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 164 | ScopedLocalRef klass(soa.Env(), 165 | soa.AddLocalReference(method->GetDeclaringClass())); 166 | ScopedThreadStateChange tsc(self, kNative); 167 | fn(soa.Env(), klass.get(), args[0], args[1]); 168 | } 169 | else if (shorty == "ZLL") 170 | { 171 | typedef jboolean(fntype)(JNIEnv *, jclass, jobject, jobject); 172 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 173 | ScopedLocalRef klass(soa.Env(), 174 | soa.AddLocalReference(method->GetDeclaringClass())); 175 | ScopedLocalRef arg0(soa.Env(), 176 | soa.AddLocalReference( 177 | reinterpret_cast(args[0]))); 178 | ScopedLocalRef arg1(soa.Env(), 179 | soa.AddLocalReference( 180 | reinterpret_cast(args[1]))); 181 | ScopedThreadStateChange tsc(self, kNative); 182 | result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get())); 183 | } 184 | else if (shorty == "ZILL") 185 | { 186 | typedef jboolean(fntype)(JNIEnv *, jclass, jint, jobject, jobject); 187 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 188 | ScopedLocalRef klass(soa.Env(), 189 | soa.AddLocalReference(method->GetDeclaringClass())); 190 | ScopedLocalRef arg1(soa.Env(), 191 | soa.AddLocalReference( 192 | reinterpret_cast(args[1]))); 193 | ScopedLocalRef arg2(soa.Env(), 194 | soa.AddLocalReference( 195 | reinterpret_cast(args[2]))); 196 | ScopedThreadStateChange tsc(self, kNative); 197 | result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get())); 198 | } 199 | else if (shorty == "VILII") 200 | { 201 | typedef void(fntype)(JNIEnv *, jclass, jint, jobject, jint, jint); 202 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 203 | ScopedLocalRef klass(soa.Env(), 204 | soa.AddLocalReference(method->GetDeclaringClass())); 205 | ScopedLocalRef arg1(soa.Env(), 206 | soa.AddLocalReference( 207 | reinterpret_cast(args[1]))); 208 | ScopedThreadStateChange tsc(self, kNative); 209 | fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]); 210 | } 211 | else if (shorty == "VLILII") 212 | { 213 | typedef void(fntype)(JNIEnv *, jclass, jobject, jint, jobject, jint, jint); 214 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 215 | ScopedLocalRef klass(soa.Env(), 216 | soa.AddLocalReference(method->GetDeclaringClass())); 217 | ScopedLocalRef arg0(soa.Env(), 218 | soa.AddLocalReference( 219 | reinterpret_cast(args[0]))); 220 | ScopedLocalRef arg2(soa.Env(), 221 | soa.AddLocalReference( 222 | reinterpret_cast(args[2]))); 223 | ScopedThreadStateChange tsc(self, kNative); 224 | fn(soa.Env(), klass.get(), arg0.get(), args[1], arg2.get(), args[3], args[4]); 225 | } 226 | else 227 | { 228 | LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method) 229 | << " shorty: " << shorty; 230 | } 231 | } 232 | else 233 | { 234 | if (shorty == "L") 235 | { 236 | typedef jobject(fntype)(JNIEnv *, jobject); 237 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 238 | ScopedLocalRef rcvr(soa.Env(), 239 | soa.AddLocalReference(receiver)); 240 | jobject jresult; 241 | { 242 | ScopedThreadStateChange tsc(self, kNative); 243 | jresult = fn(soa.Env(), rcvr.get()); 244 | } 245 | result->SetL(soa.Decode(jresult)); 246 | } 247 | else if (shorty == "V") 248 | { 249 | typedef void(fntype)(JNIEnv *, jobject); 250 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 251 | ScopedLocalRef rcvr(soa.Env(), 252 | soa.AddLocalReference(receiver)); 253 | ScopedThreadStateChange tsc(self, kNative); 254 | fn(soa.Env(), rcvr.get()); 255 | } 256 | else if (shorty == "LL") 257 | { 258 | typedef jobject(fntype)(JNIEnv *, jobject, jobject); 259 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 260 | ScopedLocalRef rcvr(soa.Env(), 261 | soa.AddLocalReference(receiver)); 262 | ScopedLocalRef arg0(soa.Env(), 263 | soa.AddLocalReference( 264 | reinterpret_cast(args[0]))); 265 | jobject jresult; 266 | { 267 | ScopedThreadStateChange tsc(self, kNative); 268 | jresult = fn(soa.Env(), rcvr.get(), arg0.get()); 269 | } 270 | result->SetL(soa.Decode(jresult)); 271 | ScopedThreadStateChange tsc(self, kNative); 272 | } 273 | else if (shorty == "III") 274 | { 275 | typedef jint(fntype)(JNIEnv *, jobject, jint, jint); 276 | fntype *const fn = reinterpret_cast(method->GetEntryPointFromJni()); 277 | ScopedLocalRef rcvr(soa.Env(), 278 | soa.AddLocalReference(receiver)); 279 | ScopedThreadStateChange tsc(self, kNative); 280 | result->SetI(fn(soa.Env(), rcvr.get(), args[0], args[1])); 281 | } 282 | else 283 | { 284 | LOG(FATAL) << "Do something with native method: " << PrettyMethod(method) 285 | << " shorty: " << shorty; 286 | } 287 | } 288 | } 289 | 290 | enum InterpreterImplKind 291 | { 292 | kSwitchImplKind, // Switch-based interpreter implementation. 293 | kComputedGotoImplKind, // Computed-goto-based interpreter implementation. 294 | kMterpImplKind // Assembly interpreter 295 | }; 296 | static std::ostream &operator<<(std::ostream &os, const InterpreterImplKind &rhs) 297 | { 298 | os << ((rhs == kSwitchImplKind) 299 | ? "Switch-based interpreter" 300 | : (rhs == kComputedGotoImplKind) 301 | ? "Computed-goto-based interpreter" 302 | : "Asm interpreter"); 303 | return os; 304 | } 305 | 306 | /* AUPK Begin */ 307 | // 改为使用 switch 型解释器 308 | //static constexpr InterpreterImplKind kInterpreterImplKind = kMterpImplKind; 309 | static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImplKind; 310 | /* AUPK End */ 311 | 312 | #if defined(__clang__) 313 | // Clang 3.4 fails to build the goto interpreter implementation. 314 | template 315 | JValue ExecuteGotoImpl(Thread *, const DexFile::CodeItem *, ShadowFrame &, JValue) 316 | { 317 | LOG(FATAL) << "UNREACHABLE"; 318 | UNREACHABLE(); 319 | } 320 | // Explicit definitions of ExecuteGotoImpl. 321 | template <> 322 | SHARED_REQUIRES(Locks::mutator_lock_) 323 | JValue ExecuteGotoImpl(Thread *self, const DexFile::CodeItem *code_item, 324 | ShadowFrame &shadow_frame, JValue result_register); 325 | template <> 326 | SHARED_REQUIRES(Locks::mutator_lock_) 327 | JValue ExecuteGotoImpl(Thread *self, const DexFile::CodeItem *code_item, 328 | ShadowFrame &shadow_frame, JValue result_register); 329 | template <> 330 | SHARED_REQUIRES(Locks::mutator_lock_) 331 | JValue ExecuteGotoImpl(Thread *self, const DexFile::CodeItem *code_item, 332 | ShadowFrame &shadow_frame, JValue result_register); 333 | template <> 334 | SHARED_REQUIRES(Locks::mutator_lock_) 335 | JValue ExecuteGotoImpl(Thread *self, const DexFile::CodeItem *code_item, 336 | ShadowFrame &shadow_frame, JValue result_register); 337 | #endif 338 | 339 | static inline JValue Execute( 340 | Thread *self, 341 | const DexFile::CodeItem *code_item, 342 | ShadowFrame &shadow_frame, 343 | JValue result_register, 344 | bool stay_in_interpreter = false) SHARED_REQUIRES(Locks::mutator_lock_) 345 | { 346 | // ArtMethod *artMethod = shadow_frame.GetMethod(); 347 | // bool isFakeInvokeMethod = Aupk::isFakeInvoke(self, artMethod); 348 | 349 | // if (!isFakeInvokeMethod && strstr(PrettyMethod(shadow_frame.GetMethod()).c_str(), "") != nullptr) 350 | // { 351 | 352 | // const DexFile *dexFile = artMethod->GetDexFile(); 353 | // char feature[] = "Execute"; 354 | // Aupk::dumpDexFile(dexFile, feature); 355 | // Aupk::dumpClassName(dexFile, feature); 356 | // } 357 | 358 | DCHECK(!shadow_frame.GetMethod()->IsAbstract()); 359 | DCHECK(!shadow_frame.GetMethod()->IsNative()); 360 | if (LIKELY(shadow_frame.GetDexPC() == 0)) 361 | { // Entering the method, but not via deoptimization. 362 | if (kIsDebugBuild) 363 | { 364 | self->AssertNoPendingException(); 365 | } 366 | instrumentation::Instrumentation *instrumentation = Runtime::Current()->GetInstrumentation(); 367 | ArtMethod *method = shadow_frame.GetMethod(); 368 | 369 | if (UNLIKELY(instrumentation->HasMethodEntryListeners())) 370 | { 371 | instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), 372 | method, 0); 373 | } 374 | 375 | if (!stay_in_interpreter) 376 | { 377 | jit::Jit *jit = Runtime::Current()->GetJit(); 378 | if (jit != nullptr) 379 | { 380 | jit->MethodEntered(self, shadow_frame.GetMethod()); 381 | if (jit->CanInvokeCompiledCode(method)) 382 | { 383 | JValue result; 384 | 385 | // Pop the shadow frame before calling into compiled code. 386 | self->PopShadowFrame(); 387 | ArtInterpreterToCompiledCodeBridge(self, nullptr, code_item, &shadow_frame, &result); 388 | // Push the shadow frame back as the caller will expect it. 389 | self->PushShadowFrame(&shadow_frame); 390 | 391 | return result; 392 | } 393 | } 394 | } 395 | } 396 | 397 | shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self); 398 | 399 | // Lock counting is a special version of accessibility checks, and for simplicity and 400 | // reduction of template parameters, we gate it behind access-checks mode. 401 | ArtMethod *method = shadow_frame.GetMethod(); 402 | DCHECK(!method->SkipAccessChecks() || !method->MustCountLocks()); 403 | 404 | 405 | bool transaction_active = Runtime::Current()->IsActiveTransaction(); 406 | if (LIKELY(method->SkipAccessChecks())) 407 | { 408 | // Enter the "without access check" interpreter. 409 | if (kInterpreterImplKind == kMterpImplKind) 410 | { 411 | if (transaction_active) 412 | { 413 | // No Mterp variant - just use the switch interpreter. 414 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 415 | false); 416 | } 417 | else if (UNLIKELY(!Runtime::Current()->IsStarted())) 418 | { 419 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 420 | false); 421 | } 422 | else 423 | { 424 | while (true) 425 | { 426 | // Mterp does not support all instrumentation/debugging. 427 | if (MterpShouldSwitchInterpreters()) 428 | { 429 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 430 | false); 431 | } 432 | bool returned = ExecuteMterpImpl(self, code_item, &shadow_frame, &result_register); 433 | if (returned) 434 | { 435 | return result_register; 436 | } 437 | else 438 | { 439 | // Mterp didn't like that instruction. Single-step it with the reference interpreter. 440 | result_register = ExecuteSwitchImpl(self, code_item, shadow_frame, 441 | result_register, true); 442 | if (shadow_frame.GetDexPC() == DexFile::kDexNoIndex) 443 | { 444 | // Single-stepped a return or an exception not handled locally. Return to caller. 445 | return result_register; 446 | } 447 | } 448 | } 449 | } 450 | } 451 | else if (kInterpreterImplKind == kSwitchImplKind) 452 | { 453 | if (transaction_active) 454 | { 455 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 456 | false); 457 | } 458 | else 459 | { 460 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 461 | false); 462 | } 463 | } 464 | else 465 | { 466 | DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind); 467 | if (transaction_active) 468 | { 469 | return ExecuteGotoImpl(self, code_item, shadow_frame, result_register); 470 | } 471 | else 472 | { 473 | return ExecuteGotoImpl(self, code_item, shadow_frame, result_register); 474 | } 475 | } 476 | } 477 | else 478 | { 479 | // Enter the "with access check" interpreter. 480 | if (kInterpreterImplKind == kMterpImplKind) 481 | { 482 | // No access check variants for Mterp. Just use the switch version. 483 | if (transaction_active) 484 | { 485 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 486 | false); 487 | } 488 | else 489 | { 490 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 491 | false); 492 | } 493 | } 494 | else if (kInterpreterImplKind == kSwitchImplKind) 495 | { 496 | if (transaction_active) 497 | { 498 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 499 | false); 500 | } 501 | else 502 | { 503 | return ExecuteSwitchImpl(self, code_item, shadow_frame, result_register, 504 | false); 505 | } 506 | } 507 | else 508 | { 509 | DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind); 510 | if (transaction_active) 511 | { 512 | return ExecuteGotoImpl(self, code_item, shadow_frame, result_register); 513 | } 514 | else 515 | { 516 | return ExecuteGotoImpl(self, code_item, shadow_frame, result_register); 517 | } 518 | } 519 | } 520 | } 521 | 522 | void EnterInterpreterFromInvoke(Thread *self, ArtMethod *method, Object *receiver, 523 | uint32_t *args, JValue *result, 524 | bool stay_in_interpreter) 525 | { 526 | bool isFakeInvokeMethod = Aupk::isFakeInvoke(self, method); 527 | 528 | DCHECK_EQ(self, Thread::Current()); 529 | 530 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 531 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) 532 | { 533 | ThrowStackOverflowError(self); 534 | return; 535 | } 536 | 537 | const char *old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke"); 538 | const DexFile::CodeItem *code_item = method->GetCodeItem(); 539 | uint16_t num_regs; 540 | uint16_t num_ins; 541 | if (code_item != nullptr) 542 | { 543 | num_regs = code_item->registers_size_; 544 | num_ins = code_item->ins_size_; 545 | } 546 | else if (!method->IsInvokable()) 547 | { 548 | self->EndAssertNoThreadSuspension(old_cause); 549 | method->ThrowInvocationTimeError(); 550 | return; 551 | } 552 | else 553 | { 554 | DCHECK(method->IsNative()); 555 | num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty()); 556 | if (!method->IsStatic()) 557 | { 558 | num_regs++; 559 | num_ins++; 560 | } 561 | } 562 | 563 | // Set up shadow frame with matching number of reference slots to vregs. 564 | ShadowFrame *last_shadow_frame = self->GetManagedStack()->GetTopShadowFrame(); 565 | ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = 566 | CREATE_SHADOW_FRAME(num_regs, last_shadow_frame, method, /* dex pc */ 0); 567 | ShadowFrame *shadow_frame = shadow_frame_unique_ptr.get(); 568 | self->PushShadowFrame(shadow_frame); 569 | 570 | size_t cur_reg = num_regs - num_ins; 571 | if (!method->IsStatic()) 572 | { 573 | CHECK(receiver != nullptr); 574 | /* AUPK Begin */ 575 | if (isFakeInvokeMethod) 576 | { 577 | //LOG(INFO)<<"EnterInterpreterFromInvoke1"; 578 | shadow_frame->SetVReg(cur_reg, args[0]); 579 | } 580 | else 581 | { 582 | shadow_frame->SetVRegReference(cur_reg, receiver); 583 | } 584 | /* AUPK End */ 585 | ++cur_reg; 586 | } 587 | uint32_t shorty_len = 0; 588 | const char *shorty = method->GetShorty(&shorty_len); 589 | //LOG(INFO)<<"method name1:"<SetVReg(cur_reg, args[arg_pos]); 602 | } 603 | else 604 | { 605 | Object *o = reinterpret_cast *>(&args[arg_pos])->AsMirrorPtr(); 606 | shadow_frame->SetVRegReference(cur_reg, o); 607 | } 608 | /* AUPK End */ 609 | break; 610 | } 611 | case 'J': 612 | case 'D': 613 | { 614 | uint64_t wide_value = (static_cast(args[arg_pos + 1]) << 32) | args[arg_pos]; 615 | shadow_frame->SetVRegLong(cur_reg, wide_value); 616 | cur_reg++; 617 | arg_pos++; 618 | break; 619 | } 620 | default: 621 | shadow_frame->SetVReg(cur_reg, args[arg_pos]); 622 | break; 623 | } 624 | } 625 | self->EndAssertNoThreadSuspension(old_cause); 626 | // Do this after populating the shadow frame in case EnsureInitialized causes a GC. 627 | if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitialized())) 628 | { 629 | ClassLinker *class_linker = Runtime::Current()->GetClassLinker(); 630 | StackHandleScope<1> hs(self); 631 | Handle h_class(hs.NewHandle(method->GetDeclaringClass())); 632 | if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) 633 | { 634 | CHECK(self->IsExceptionPending()); 635 | self->PopShadowFrame(); 636 | return; 637 | } 638 | } 639 | if (LIKELY(!method->IsNative())) 640 | { 641 | JValue r = Execute(self, code_item, *shadow_frame, JValue(), stay_in_interpreter); 642 | if (result != nullptr) 643 | { 644 | *result = r; 645 | } 646 | } 647 | else 648 | { 649 | //LOG(INFO)<<"method name1:"<GetVRegArgs(method->IsStatic() ? 0 : 1); 655 | if (!Runtime::Current()->IsStarted()) 656 | { 657 | //LOG(INFO)<<"method name2:"<PopShadowFrame(); 667 | } 668 | 669 | static bool IsStringInit(const Instruction *instr, ArtMethod *caller) 670 | SHARED_REQUIRES(Locks::mutator_lock_) 671 | { 672 | if (instr->Opcode() == Instruction::INVOKE_DIRECT || 673 | instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) 674 | { 675 | // Instead of calling ResolveMethod() which has suspend point and can trigger 676 | // GC, look up the callee method symbolically. 677 | uint16_t callee_method_idx = (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ? instr->VRegB_3rc() : instr->VRegB_35c(); 678 | const DexFile *dex_file = caller->GetDexFile(); 679 | const DexFile::MethodId &method_id = dex_file->GetMethodId(callee_method_idx); 680 | const char *class_name = dex_file->StringByTypeIdx(method_id.class_idx_); 681 | const char *method_name = dex_file->GetMethodName(method_id); 682 | // Compare method's class name and method name against string init. 683 | // It's ok since it's not allowed to create your own java/lang/String. 684 | // TODO: verify that assumption. 685 | if ((strcmp(class_name, "Ljava/lang/String;") == 0) && 686 | (strcmp(method_name, "") == 0)) 687 | { 688 | return true; 689 | } 690 | } 691 | return false; 692 | } 693 | 694 | static int16_t GetReceiverRegisterForStringInit(const Instruction *instr) 695 | { 696 | DCHECK(instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE || 697 | instr->Opcode() == Instruction::INVOKE_DIRECT); 698 | return (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ? instr->VRegC_3rc() : instr->VRegC_35c(); 699 | } 700 | 701 | void EnterInterpreterFromDeoptimize(Thread *self, 702 | ShadowFrame *shadow_frame, 703 | bool from_code, 704 | JValue *ret_val) 705 | SHARED_REQUIRES(Locks::mutator_lock_) 706 | { 707 | JValue value; 708 | // Set value to last known result in case the shadow frame chain is empty. 709 | value.SetJ(ret_val->GetJ()); 710 | // Are we executing the first shadow frame? 711 | bool first = true; 712 | while (shadow_frame != nullptr) 713 | { 714 | // We do not want to recover lock state for lock counting when deoptimizing. Currently, 715 | // the compiler should not have compiled a method that failed structured-locking checks. 716 | DCHECK(!shadow_frame->GetMethod()->MustCountLocks()); 717 | 718 | self->SetTopOfShadowStack(shadow_frame); 719 | const DexFile::CodeItem *code_item = shadow_frame->GetMethod()->GetCodeItem(); 720 | const uint32_t dex_pc = shadow_frame->GetDexPC(); 721 | uint32_t new_dex_pc = dex_pc; 722 | if (UNLIKELY(self->IsExceptionPending())) 723 | { 724 | // If we deoptimize from the QuickExceptionHandler, we already reported the exception to 725 | // the instrumentation. To prevent from reporting it a second time, we simply pass a 726 | // null Instrumentation*. 727 | const instrumentation::Instrumentation *const instrumentation = 728 | first ? nullptr : Runtime::Current()->GetInstrumentation(); 729 | uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame, dex_pc, 730 | instrumentation); 731 | new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler 732 | // or DexFile::kDexNoIndex if there is none. 733 | } 734 | else if (!from_code) 735 | { 736 | // For the debugger and full deoptimization stack, we must go past the invoke 737 | // instruction, as it already executed. 738 | // TODO: should be tested more once b/17586779 is fixed. 739 | const Instruction *instr = Instruction::At(&code_item->insns_[dex_pc]); 740 | if (instr->IsInvoke()) 741 | { 742 | if (IsStringInit(instr, shadow_frame->GetMethod())) 743 | { 744 | uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr); 745 | // Move the StringFactory.newStringFromChars() result into the register representing 746 | // "this object" when invoking the string constructor in the original dex instruction. 747 | // Also move the result into all aliases. 748 | DCHECK(value.GetL()->IsString()); 749 | SetStringInitValueToAllAliases(shadow_frame, this_obj_vreg, value); 750 | // Calling string constructor in the original dex code doesn't generate a result value. 751 | value.SetJ(0); 752 | } 753 | new_dex_pc = dex_pc + instr->SizeInCodeUnits(); 754 | } 755 | else if (instr->Opcode() == Instruction::NEW_INSTANCE) 756 | { 757 | // It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a 758 | // java string, which is turned into a call into StringFactory.newEmptyString(); 759 | // Move the StringFactory.newEmptyString() result into the destination register. 760 | DCHECK(value.GetL()->IsString()); 761 | shadow_frame->SetVRegReference(instr->VRegA_21c(), value.GetL()); 762 | // new-instance doesn't generate a result value. 763 | value.SetJ(0); 764 | // Skip the dex instruction since we essentially come back from an invocation. 765 | new_dex_pc = dex_pc + instr->SizeInCodeUnits(); 766 | if (kIsDebugBuild) 767 | { 768 | ClassLinker *class_linker = Runtime::Current()->GetClassLinker(); 769 | // This is a suspend point. But it's ok since value has been set into shadow_frame. 770 | mirror::Class *klass = class_linker->ResolveType( 771 | instr->VRegB_21c(), shadow_frame->GetMethod()); 772 | DCHECK(klass->IsStringClass()); 773 | } 774 | } 775 | else 776 | { 777 | CHECK(false) << "Unexpected instruction opcode " << instr->Opcode() 778 | << " at dex_pc " << dex_pc 779 | << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false); 780 | } 781 | } 782 | else 783 | { 784 | // Nothing to do, the dex_pc is the one at which the code requested 785 | // the deoptimization. 786 | } 787 | if (new_dex_pc != DexFile::kDexNoIndex) 788 | { 789 | shadow_frame->SetDexPC(new_dex_pc); 790 | value = Execute(self, code_item, *shadow_frame, value); 791 | } 792 | ShadowFrame *old_frame = shadow_frame; 793 | shadow_frame = shadow_frame->GetLink(); 794 | ShadowFrame::DeleteDeoptimizedFrame(old_frame); 795 | // Following deoptimizations of shadow frames must pass the invoke instruction. 796 | from_code = false; 797 | first = false; 798 | } 799 | ret_val->SetJ(value.GetJ()); 800 | } 801 | 802 | JValue EnterInterpreterFromEntryPoint(Thread *self, const DexFile::CodeItem *code_item, 803 | ShadowFrame *shadow_frame) 804 | { 805 | DCHECK_EQ(self, Thread::Current()); 806 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 807 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) 808 | { 809 | ThrowStackOverflowError(self); 810 | return JValue(); 811 | } 812 | 813 | jit::Jit *jit = Runtime::Current()->GetJit(); 814 | if (jit != nullptr) 815 | { 816 | jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod()); 817 | } 818 | return Execute(self, code_item, *shadow_frame, JValue()); 819 | } 820 | 821 | void ArtInterpreterToInterpreterBridge(Thread *self, const DexFile::CodeItem *code_item, 822 | ShadowFrame *shadow_frame, JValue *result) 823 | { 824 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 825 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) 826 | { 827 | ThrowStackOverflowError(self); 828 | return; 829 | } 830 | 831 | self->PushShadowFrame(shadow_frame); 832 | ArtMethod *method = shadow_frame->GetMethod(); 833 | // Ensure static methods are initialized. 834 | const bool is_static = method->IsStatic(); 835 | if (is_static) 836 | { 837 | mirror::Class *declaring_class = method->GetDeclaringClass(); 838 | if (UNLIKELY(!declaring_class->IsInitialized())) 839 | { 840 | StackHandleScope<1> hs(self); 841 | HandleWrapper h_declaring_class(hs.NewHandleWrapper(&declaring_class)); 842 | if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized( 843 | self, h_declaring_class, true, true))) 844 | { 845 | DCHECK(self->IsExceptionPending()); 846 | self->PopShadowFrame(); 847 | return; 848 | } 849 | CHECK(h_declaring_class->IsInitializing()); 850 | } 851 | } 852 | 853 | if (LIKELY(!shadow_frame->GetMethod()->IsNative())) 854 | { 855 | result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ()); 856 | } 857 | else 858 | { 859 | // We don't expect to be asked to interpret native code (which is entered via a JNI compiler 860 | // generated stub) except during testing and image writing. 861 | CHECK(!Runtime::Current()->IsStarted()); 862 | Object *receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0); 863 | uint32_t *args = shadow_frame->GetVRegArgs(is_static ? 0 : 1); 864 | UnstartedRuntime::Jni(self, shadow_frame->GetMethod(), receiver, args, result); 865 | } 866 | 867 | self->PopShadowFrame(); 868 | } 869 | 870 | void CheckInterpreterAsmConstants() 871 | { 872 | CheckMterpAsmConstants(); 873 | } 874 | 875 | void InitInterpreterTls(Thread *self) 876 | { 877 | InitMterpTls(self); 878 | } 879 | 880 | } // namespace interpreter 881 | } // namespace art 882 | -------------------------------------------------------------------------------- /art/runtime/native/aupk_method.cc: -------------------------------------------------------------------------------- 1 | #include "art_method-inl.h" 2 | #include "class_linker.h" 3 | #include "class_linker-inl.h" 4 | #include "jni_internal.h" 5 | #include "mirror/class-inl.h" 6 | #include "mirror/object-inl.h" 7 | #include "mirror/object_array-inl.h" 8 | #include "reflection.h" 9 | #include "scoped_fast_native_object_access.h" 10 | #include "well_known_classes.h" 11 | 12 | namespace art 13 | { 14 | extern "C" ArtMethod *jMethodToArtMethod(JNIEnv *env, jobject jMethod) 15 | { 16 | ScopedFastNativeObjectAccess soa(env); 17 | ArtMethod *method = ArtMethod::FromReflectedMethod(soa, jMethod); 18 | return method; 19 | } 20 | } -------------------------------------------------------------------------------- /frameworks/base/core/java/android/app/Aupk.java: -------------------------------------------------------------------------------- 1 | package android.app; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileInputStream; 5 | import java.io.OutputStream; 6 | import java.io.FileWriter; 7 | import java.io.InputStreamReader; 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.InvocationTargetException; 10 | import java.lang.reflect.Method; 11 | import java.lang.reflect.Modifier; 12 | import java.util.HashMap; 13 | import java.lang.reflect.Constructor; 14 | import dalvik.system.BaseDexClassLoader; 15 | import dalvik.system.DexClassLoader; 16 | import android.app.Application; 17 | import org.json.JSONArray; 18 | import org.json.JSONException; 19 | import org.json.JSONObject; 20 | import java.util.Iterator; 21 | import android.util.Log; 22 | import android.util.LogPrinter; 23 | import java.util.Map; 24 | import java.io.File; 25 | import java.util.List; 26 | import java.util.ArrayList; 27 | 28 | public class Aupk 29 | { 30 | class FileInfo 31 | { 32 | public String fileName; 33 | public List classList=new ArrayList<>(); 34 | } 35 | class ClassInfo 36 | { 37 | public String className; 38 | public Map methodMap=new HashMap(); 39 | } 40 | 41 | public static Object getFieldOjbect(String class_name, Object obj, String filedName) 42 | { 43 | try 44 | { 45 | Class obj_class = Class.forName(class_name); 46 | Field field = obj_class.getDeclaredField(filedName); 47 | field.setAccessible(true); 48 | return field.get(obj); 49 | } 50 | catch (Exception e) 51 | { 52 | e.printStackTrace(); 53 | } 54 | return null; 55 | } 56 | 57 | public static ClassLoader getClassLoader() 58 | { 59 | ClassLoader resultClassloader = null; 60 | try 61 | { 62 | Class class_ActivityThread = Class.forName("android.app.ActivityThread"); 63 | Method method = class_ActivityThread.getMethod("currentActivityThread", new Class[]{}); 64 | Object currentActivityThread = method.invoke(null, new Object[]{}); 65 | 66 | Object mBoundApplication = getFieldOjbect( 67 | "android.app.ActivityThread", 68 | currentActivityThread, 69 | "mBoundApplication" 70 | ); 71 | Object loadedApkInfo = getFieldOjbect( 72 | "android.app.ActivityThread$AppBindData", 73 | mBoundApplication, 74 | "info" 75 | ); 76 | Application mApplication = (Application) getFieldOjbect( 77 | "android.app.LoadedApk", 78 | loadedApkInfo, 79 | "mApplication" 80 | ); 81 | resultClassloader = mApplication.getClassLoader(); 82 | } 83 | catch (Exception e) 84 | { 85 | e.printStackTrace(); 86 | } 87 | 88 | return resultClassloader; 89 | } 90 | 91 | 92 | public static Method getMethod(ClassLoader appClassLoader, String className, String methodName) 93 | { 94 | Class class_DexFileClazz = null; 95 | try 96 | { 97 | class_DexFileClazz = appClassLoader.loadClass(className); 98 | for (Method method : class_DexFileClazz.getDeclaredMethods()) 99 | { 100 | if (method.getName().equals(methodName)) 101 | { 102 | method.setAccessible(true); 103 | return method; 104 | } 105 | } 106 | } 107 | catch (Exception e) 108 | { 109 | e.printStackTrace(); 110 | } 111 | return null; 112 | } 113 | 114 | static Method method_native_fakeInvoke = null; 115 | /** 116 | * 对集合里的每一个方法发起主动调用 117 | */ 118 | public static void fakeInvoke(Object method) 119 | { 120 | try 121 | { 122 | // 该方法为native方法,声明于Aupk.java,实现于dalvik_system_DexFile.cc 123 | // 用于对指定函数发起主动调用 124 | if(method_native_fakeInvoke==null) 125 | { 126 | method_native_fakeInvoke=getMethod(getClassLoader(),"android.app.Aupk","native_fakeInvoke"); 127 | } 128 | if(method==null) 129 | { 130 | return; 131 | } 132 | method_native_fakeInvoke.invoke(null, method); 133 | } 134 | catch(Exception e) 135 | { 136 | e.printStackTrace(); 137 | } 138 | 139 | } 140 | 141 | /** 142 | * 获取指定类里所有的方法 143 | * 返回类的方法数量 144 | */ 145 | public static int loadAllMethodsWithClass(Class klass,ClassInfo classInfo) 146 | { 147 | //Log.i("AUPK", "ActivityThread:loadAllMethods from class:" + className); 148 | int count=0; 149 | try 150 | { 151 | if (klass == null) 152 | { 153 | return 0; 154 | } 155 | 156 | // 获取目标类的所有构造函数 157 | Constructor constructors[] = klass.getDeclaredConstructors(); 158 | for (Object constructor : constructors) 159 | { 160 | 161 | String methodName=klass.getName()+constructor.toString(); 162 | classInfo.methodMap.put(methodName,constructor); 163 | count++; 164 | } 165 | 166 | // 获取目标类的所有成员函数 167 | Method[] methods = klass.getDeclaredMethods(); 168 | for (Method method : methods) 169 | { 170 | String methodName=klass.getName()+method.toString(); 171 | classInfo.methodMap.put(methodName,method); 172 | count++; 173 | } 174 | } 175 | catch (Error | Exception e) 176 | { 177 | e.printStackTrace(); 178 | } 179 | return count; 180 | } 181 | 182 | 183 | 184 | private static String formatTime(long ms) { 185 | int ss = 1000; 186 | int mi = ss * 60; 187 | int hh = mi * 60; 188 | int dd = hh * 24; 189 | 190 | long day = ms / dd; 191 | long hour = (ms - day * dd) / hh; 192 | long minute = (ms - day * dd - hour * hh) / mi; 193 | long second = (ms - day * dd - hour * hh - minute * mi) / ss; 194 | long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; 195 | 196 | String strHour = hour < 10 ? "0" + hour : "" + hour;//小时 197 | String strMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 198 | String strSecond = second < 10 ? "0" + second : "" + second;//秒 199 | String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 200 | strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond : "" + strMilliSecond; 201 | return strHour+":"+strMinute + ":" + strSecond+",";//+strMilliSecond ; 202 | } 203 | 204 | static Thread thread=null; 205 | public synchronized void aupkThread() 206 | { 207 | if(thread==null) 208 | { 209 | thread=new Thread(new Runnable() 210 | { 211 | @Override 212 | public void run() 213 | { 214 | String configPath="data/local/tmp/aupk.config"; 215 | while(true) 216 | { 217 | try 218 | { 219 | Thread.sleep(1000); 220 | String strConfig=readFileString(configPath); 221 | if(strConfig!=null) 222 | { 223 | Log.e("AUPK", "Found configration:"+strConfig); 224 | // 配置文件格式: 225 | // com.package.name [method_info.json] 226 | Log.e("AUPK", "Start aupk"); 227 | long startMillis = System.currentTimeMillis(); 228 | 229 | strConfig=strConfig.replace("\n",""); 230 | String[] configs = strConfig.split(" "); 231 | if(configs.length==1) 232 | { 233 | Log.i("AUPK","package name:"+configs[0]); 234 | aupkThreadClasses(configs[0],null); 235 | } 236 | else if(configs.length==2) 237 | { 238 | Log.i("AUPK","package name:"+configs[0]); 239 | Log.i("AUPK","method info name:"+configs[1]); 240 | aupkThreadClasses(configs[0],configs[1]); 241 | } 242 | else 243 | { 244 | Log.e("AUPK", "Invalid configuration file:"+configPath); 245 | continue; 246 | } 247 | 248 | Log.e("AUPK", "Aupk run over"); 249 | long endMillis = System.currentTimeMillis(); 250 | String strTime=formatTime(endMillis-startMillis); 251 | Log.e("AUPK","Time "+strTime); 252 | File file = new File(configPath); 253 | if(file.exists() && file.isFile()) 254 | { 255 | // 删除配置文件 256 | if(!file.delete()) 257 | { 258 | Log.e("AUPK", "File:"+configPath+" delete failed"); 259 | 260 | } 261 | } 262 | Log.e("AUPK", "Programe will kill the aupk thread"); 263 | thread=null; 264 | break; 265 | } 266 | } 267 | catch(Exception e) 268 | { 269 | e.printStackTrace(); 270 | 271 | } 272 | } 273 | thread=null; 274 | } 275 | }); 276 | thread.start(); 277 | } 278 | } 279 | 280 | 281 | 282 | /** 283 | * 启动主动调用线程 284 | */ 285 | public void unpackWithClassLoader(int second) 286 | { 287 | new Thread(new Runnable() 288 | { 289 | @Override 290 | public void run() 291 | { 292 | try 293 | { 294 | Log.e("AUPK", "start sleep for "+second+" seconds)......"); 295 | Thread.sleep(second* 1000); 296 | Log.e("AUPK", "sleep over and start aupkThread"); 297 | aupkThread(); 298 | Log.e("AUPK", "aupk run over"); 299 | } 300 | catch(Exception e) 301 | { 302 | e.printStackTrace(); 303 | } 304 | } 305 | }).start(); 306 | } 307 | 308 | private boolean aupkThreadClasses(String packageName,String dexClassFileName) 309 | { 310 | List fileList=new ArrayList<>(); 311 | try 312 | { 313 | //Map methodMap=new HashMap<>(); 314 | List dexClassPaths=new ArrayList<>(); 315 | String folder="data/data/"+packageName+"/aupk/"; 316 | if(dexClassFileName==null) 317 | { 318 | File file=new File(folder); 319 | File[] files = file.listFiles(); 320 | if(files==null) 321 | { 322 | return false; 323 | } 324 | for(File f:files) 325 | { 326 | if(f.getName().contains("_class.json")) 327 | { 328 | String fileName=f.getAbsolutePath(); 329 | //String fileName=folder+file.getName(); 330 | dexClassPaths.add(fileName); 331 | } 332 | } 333 | } 334 | else 335 | { 336 | String fileName=folder+dexClassFileName; 337 | dexClassPaths.add(fileName); 338 | } 339 | 340 | Method method_mapToFile = getMethod(getClassLoader(),"android.app.Aupk","mapToFile"); 341 | Log.i("AUPK","Found "+dexClassPaths.size()+" _class.json files"); 342 | for (int i = 0; i com.fighter.sdk.report.abtest.ABTestConfig$1 375 | String className =data.getString(j).substring(1,data.getString(j).length()-1).replace("/","."); 376 | if(className.equals("android.app.Aupk")) 377 | { 378 | continue; 379 | } 380 | ClassInfo classInfo=new ClassInfo(); 381 | classInfo.className=className; 382 | fileInfo.classList.add(classInfo); 383 | 384 | Class klass=getClassLoader().loadClass(className); 385 | int count=loadAllMethodsWithClass(klass,classInfo); 386 | 387 | Log.i("AUPK","Load file["+(i+1)+"/"+dexClassPaths.size()+"]:"+classesFile.getName()+",class["+(j+1)+"/"+data.length()+"]:"+className+",method count:"+count); 388 | } 389 | catch (Error | Exception e) 390 | { 391 | e.printStackTrace(); 392 | continue; 393 | } 394 | } 395 | } 396 | 397 | // 遍历方法map,并进行主动调用 398 | for(int x=0;x classList=fileList.get(x).classList; 402 | 403 | for(int y=0;y methodMap=classList.get(y).methodMap; 407 | 408 | String log="File["+(x+1)+"/"+fileList.size()+"]:"+fileName+","; 409 | log+="Class["+(y+1)+"/"+classList.size()+"]:"+className+","; 410 | Log.i("AUPK",log); 411 | 412 | for(Map.Entry entry :methodMap.entrySet()) 413 | { 414 | try 415 | { 416 | String methodName=entry.getKey(); 417 | Object method=entry.getValue(); 418 | fakeInvoke(method); 419 | } 420 | catch(Error | Exception e) 421 | { 422 | e.printStackTrace(); 423 | continue; 424 | } 425 | } 426 | } 427 | method_mapToFile.invoke(null); 428 | } 429 | return true; 430 | } 431 | catch (Exception e) 432 | { 433 | e.printStackTrace(); 434 | Log.i("AUPK","aupkThreadClasses error"); 435 | } 436 | return false; 437 | } 438 | 439 | /** 440 | * 读取配置文件 441 | */ 442 | public static String readFileString(String fileName) 443 | { 444 | FileInputStream fis=null; 445 | try 446 | { 447 | File file = new File(fileName); 448 | fis = new FileInputStream(file); 449 | int length = fis.available(); 450 | byte[] buffer = new byte[length]; 451 | fis.read(buffer); 452 | String str = new String(buffer); 453 | fis.close(); 454 | return str; 455 | } 456 | catch (Exception e) 457 | { 458 | //e.printStackTrace(); 459 | //Log.e("AUPK", "ActivityThread:readFileString,read config file failed:" +e.getMessage()+";fileName:"+fileName); 460 | } 461 | return null; 462 | } 463 | 464 | private static native void native_fakeInvoke(Object method); 465 | private static native void mapToFile(); 466 | } 467 | 468 | 469 | 470 | -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_19-56-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_19-56-55.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_19-57-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_19-57-20.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_22-43-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_22-43-16.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_22-54-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_22-54-27.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_23-08-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_23-08-22.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_23-09-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_23-09-38.png -------------------------------------------------------------------------------- /img/Snipaste_2021-03-28_23-13-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeJQ/AUPK/5b26b4ea93f869beb8e6a10359d531ddf3e7f958/img/Snipaste_2021-03-28_23-13-32.png --------------------------------------------------------------------------------