├── README.md ├── art └── runtime │ ├── Android.bp │ ├── art_method.cc │ ├── interpreter │ ├── interpreter.cc │ └── interpreter_switch_impl-inl.h │ └── native │ ├── dalvik_system_DexFile.cc │ └── java_lang_reflect_Method.cc ├── frameworks └── base │ └── core │ └── java │ ├── android │ └── app │ │ └── ActivityThread.java │ └── cn │ └── mik │ └── Fartext.java ├── img ├── image-20210804190809645.png ├── image-20210805100310939.png └── image-20210805100343385.png └── libcore └── DexFile.java /README.md: -------------------------------------------------------------------------------- 1 | # FartExt 2 | 在FART的基础上进行优化并实现更深的主动调用,来实现脱抽取壳。适用AOSP10 3 | 4 | 本人的测试版本是android 10r2,测试手机是pixel3。如需其他版本,请自行编译。 5 | 6 | 编译的版本是sailfish Pixel binaries for Android 10.0.0 (QP1A.191005.007.A1) 7 | 8 | ### 下载 9 | 10 | 链接: https://pan.baidu.com/s/1lgG8P3H2Q5B6e7rZr58cXw 密码: 033p 11 | 12 | ### 使用 13 | 14 | **1、完整主动调用** 15 | 16 | `echo "packageName" > /data/local/tmp/fext.config` 17 | 18 | 打开应用等待60秒后开始完整的主动调用。 19 | 20 | `adb logcat |grep fartext`查看日志。出现`fart over`就是脱壳完成了 21 | 22 | **2、指定类主动调用** 23 | 24 | 将要dump的所有类名写入`/data/local/tmp/目标进程包名`中。 25 | 26 | 格式可以是`com.myClass`也可以是`Lcom\myClass;`内部会自动解析 27 | 28 | **3、frida辅助调用** 29 | 30 | 可以使用[fridaUiTools](https://github.com/dqzg12300/fridaUiTools)中的fart功能中的rom主动调用来触发 31 | 32 | ![image-20210805100343385](./img/image-20210805100343385.png) 33 | 34 | 也可以自己使用frida脚本 35 | 36 | ~~~javascript 37 | function romClassesInvoke(classes){ 38 | Java.perform(function(){ 39 | klog("romClassesInvoke start load"); 40 | var fartExt=Java.use("cn.mik.Fartext"); 41 | if(!fartExt.fartWithClassList){ 42 | klog("fartExt中未找到fartWithClassList函数,可能是未使用Fartext的rom") 43 | return ; 44 | } 45 | fartExt.fartWithClassList(classes); 46 | }) 47 | } 48 | 49 | function romFartAllClassLoader(){ 50 | Java.perform(function(){ 51 | var fartExt=Java.use("cn.mik.Fartext"); 52 | if(!fartExt.fartWithClassLoader){ 53 | klog("fartExt中未找到fartWithClassLoader函数,可能是未使用Fartext的rom"); 54 | return; 55 | } 56 | Java.enumerateClassLoadersSync().forEach(function(loader){ 57 | klog("romFartAllClassLoader to loader:"+loader); 58 | if(loader.toString().indexOf("BootClassLoader")==-1){ 59 | klog("fart start loader:"+loader); 60 | fartExt.fartWithClassLoader(loader); 61 | } 62 | }) 63 | }); 64 | } 65 | ~~~ 66 | 67 | **4、修复dex** 68 | 69 | 脱壳的结果是保存在`/sdcard/fext/目标进程包名`中 70 | 71 | 使用[dexfixer](https://github.com/dqzg12300/dexfixer)修复 72 | 73 | `java -jar ./dexfixer.jar dexpath binpath outpath` 74 | 75 | 或者使用[fridaUiTools](https://github.com/dqzg12300/fridaUiTools)的辅助功能进行修复 76 | 77 | ![image-20210805100310939](./img/image-20210805100310939.png) 78 | 79 | **5、日志查看** 80 | 81 | logcat搜索fartext即可搜到所有相关日志。 82 | 83 | **6、流程图** 84 | 85 | ![image-20210804190809645](./img/image-20210804190809645.png) 86 | 87 | ### 7、实现原理及案例 88 | 89 | > [FartExt之优化更深主动调用的FART10](https://bbs.pediy.com/thread-268760.htm) 90 | 91 | -------------------------------------------------------------------------------- /art/runtime/Android.bp: -------------------------------------------------------------------------------- 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 | // Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where 18 | // we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when 19 | // new jit code is generated. We don't want it to be called when a different function with the same 20 | // (empty) body is called. 21 | JIT_DEBUG_REGISTER_CODE_LDFLAGS = [ 22 | "-Wl,--keep-unique,__jit_debug_register_code", 23 | "-Wl,--keep-unique,__dex_debug_register_code", 24 | 25 | ] 26 | 27 | libart_cc_defaults { 28 | name: "libart_defaults", 29 | defaults: ["art_defaults"], 30 | host_supported: true, 31 | srcs: [ 32 | "aot_class_linker.cc", 33 | "art_field.cc", 34 | "art_method.cc", 35 | "backtrace_helper.cc", 36 | "barrier.cc", 37 | "base/locks.cc", 38 | "base/mem_map_arena_pool.cc", 39 | "base/mutex.cc", 40 | "base/quasi_atomic.cc", 41 | "base/timing_logger.cc", 42 | "cha.cc", 43 | "class_linker.cc", 44 | "class_loader_context.cc", 45 | "class_root.cc", 46 | "class_table.cc", 47 | "common_throws.cc", 48 | "compiler_filter.cc", 49 | "debug_print.cc", 50 | "debugger.cc", 51 | "dex/dex_file_annotations.cc", 52 | "dex_register_location.cc", 53 | "dex_to_dex_decompiler.cc", 54 | "elf_file.cc", 55 | "exec_utils.cc", 56 | "fault_handler.cc", 57 | "gc/allocation_record.cc", 58 | "gc/allocator/dlmalloc.cc", 59 | "gc/allocator/rosalloc.cc", 60 | "gc/accounting/bitmap.cc", 61 | "gc/accounting/card_table.cc", 62 | "gc/accounting/heap_bitmap.cc", 63 | "gc/accounting/mod_union_table.cc", 64 | "gc/accounting/remembered_set.cc", 65 | "gc/accounting/space_bitmap.cc", 66 | "gc/collector/concurrent_copying.cc", 67 | "gc/collector/garbage_collector.cc", 68 | "gc/collector/immune_region.cc", 69 | "gc/collector/immune_spaces.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 | "gc/verification.cc", 90 | "hidden_api.cc", 91 | "hprof/hprof.cc", 92 | "image.cc", 93 | "index_bss_mapping.cc", 94 | "indirect_reference_table.cc", 95 | "instrumentation.cc", 96 | "intern_table.cc", 97 | "interpreter/interpreter.cc", 98 | "interpreter/interpreter_cache.cc", 99 | "interpreter/interpreter_common.cc", 100 | "interpreter/interpreter_intrinsics.cc", 101 | "interpreter/interpreter_switch_impl0.cc", 102 | "interpreter/interpreter_switch_impl1.cc", 103 | "interpreter/interpreter_switch_impl2.cc", 104 | "interpreter/interpreter_switch_impl3.cc", 105 | "interpreter/lock_count_data.cc", 106 | "interpreter/shadow_frame.cc", 107 | "interpreter/unstarted_runtime.cc", 108 | "java_frame_root_info.cc", 109 | "jdwp/jdwp_event.cc", 110 | "jdwp/jdwp_expand_buf.cc", 111 | "jdwp/jdwp_handler.cc", 112 | "jdwp/jdwp_main.cc", 113 | "jdwp/jdwp_request.cc", 114 | "jdwp/jdwp_socket.cc", 115 | "jdwp/object_registry.cc", 116 | "jit/debugger_interface.cc", 117 | "jit/jit.cc", 118 | "jit/jit_code_cache.cc", 119 | "jit/profiling_info.cc", 120 | "jit/profile_saver.cc", 121 | "jni/check_jni.cc", 122 | "jni/java_vm_ext.cc", 123 | "jni/jni_env_ext.cc", 124 | "jni/jni_internal.cc", 125 | "linear_alloc.cc", 126 | "managed_stack.cc", 127 | "method_handles.cc", 128 | "mirror/array.cc", 129 | "mirror/class.cc", 130 | "mirror/class_ext.cc", 131 | "mirror/dex_cache.cc", 132 | "mirror/emulated_stack_frame.cc", 133 | "mirror/executable.cc", 134 | "mirror/field.cc", 135 | "mirror/method.cc", 136 | "mirror/method_handle_impl.cc", 137 | "mirror/method_handles_lookup.cc", 138 | "mirror/method_type.cc", 139 | "mirror/object.cc", 140 | "mirror/stack_trace_element.cc", 141 | "mirror/string.cc", 142 | "mirror/throwable.cc", 143 | "mirror/var_handle.cc", 144 | "monitor.cc", 145 | "monitor_objects_stack_visitor.cc", 146 | "native_bridge_art_interface.cc", 147 | "native_stack_dump.cc", 148 | "native/dalvik_system_DexFile.cc", 149 | "native/dalvik_system_VMDebug.cc", 150 | "native/dalvik_system_VMRuntime.cc", 151 | "native/dalvik_system_VMStack.cc", 152 | "native/dalvik_system_ZygoteHooks.cc", 153 | "native/java_lang_Class.cc", 154 | "native/java_lang_Object.cc", 155 | "native/java_lang_String.cc", 156 | "native/java_lang_StringFactory.cc", 157 | "native/java_lang_System.cc", 158 | "native/java_lang_Thread.cc", 159 | "native/java_lang_Throwable.cc", 160 | "native/java_lang_VMClassLoader.cc", 161 | "native/java_lang_invoke_MethodHandleImpl.cc", 162 | "native/java_lang_ref_FinalizerReference.cc", 163 | "native/java_lang_ref_Reference.cc", 164 | "native/java_lang_reflect_Array.cc", 165 | "native/java_lang_reflect_Constructor.cc", 166 | "native/java_lang_reflect_Executable.cc", 167 | "native/java_lang_reflect_Field.cc", 168 | "native/java_lang_reflect_Method.cc", 169 | "native/java_lang_reflect_Parameter.cc", 170 | "native/java_lang_reflect_Proxy.cc", 171 | "native/java_util_concurrent_atomic_AtomicLong.cc", 172 | "native/libcore_util_CharsetUtils.cc", 173 | "native/org_apache_harmony_dalvik_ddmc_DdmServer.cc", 174 | "native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc", 175 | "native/sun_misc_Unsafe.cc", 176 | "non_debuggable_classes.cc", 177 | "oat.cc", 178 | "oat_file.cc", 179 | "oat_file_assistant.cc", 180 | "oat_file_manager.cc", 181 | "oat_quick_method_header.cc", 182 | "object_lock.cc", 183 | "offsets.cc", 184 | "parsed_options.cc", 185 | "plugin.cc", 186 | "quick_exception_handler.cc", 187 | "read_barrier.cc", 188 | "reference_table.cc", 189 | "reflection.cc", 190 | "runtime.cc", 191 | "runtime_callbacks.cc", 192 | "runtime_common.cc", 193 | "runtime_intrinsics.cc", 194 | "runtime_options.cc", 195 | "scoped_thread_state_change.cc", 196 | "signal_catcher.cc", 197 | "stack.cc", 198 | "stack_map.cc", 199 | "thread.cc", 200 | "thread_list.cc", 201 | "thread_pool.cc", 202 | "ti/agent.cc", 203 | "trace.cc", 204 | "transaction.cc", 205 | "var_handles.cc", 206 | "vdex_file.cc", 207 | "verifier/class_verifier.cc", 208 | "verifier/instruction_flags.cc", 209 | "verifier/method_verifier.cc", 210 | "verifier/reg_type.cc", 211 | "verifier/reg_type_cache.cc", 212 | "verifier/register_line.cc", 213 | "verifier/verifier_deps.cc", 214 | "verify_object.cc", 215 | "well_known_classes.cc", 216 | 217 | "arch/context.cc", 218 | "arch/instruction_set_features.cc", 219 | "arch/memcmp16.cc", 220 | "arch/arm/instruction_set_features_arm.cc", 221 | "arch/arm/registers_arm.cc", 222 | "arch/arm64/instruction_set_features_arm64.cc", 223 | "arch/arm64/registers_arm64.cc", 224 | "arch/mips/instruction_set_features_mips.cc", 225 | "arch/mips/registers_mips.cc", 226 | "arch/mips64/instruction_set_features_mips64.cc", 227 | "arch/mips64/registers_mips64.cc", 228 | "arch/x86/instruction_set_features_x86.cc", 229 | "arch/x86/registers_x86.cc", 230 | "arch/x86_64/registers_x86_64.cc", 231 | "entrypoints/entrypoint_utils.cc", 232 | "entrypoints/jni/jni_entrypoints.cc", 233 | "entrypoints/math_entrypoints.cc", 234 | "entrypoints/quick/quick_alloc_entrypoints.cc", 235 | "entrypoints/quick/quick_cast_entrypoints.cc", 236 | "entrypoints/quick/quick_deoptimization_entrypoints.cc", 237 | "entrypoints/quick/quick_dexcache_entrypoints.cc", 238 | "entrypoints/quick/quick_entrypoints_enum.cc", 239 | "entrypoints/quick/quick_field_entrypoints.cc", 240 | "entrypoints/quick/quick_fillarray_entrypoints.cc", 241 | "entrypoints/quick/quick_jni_entrypoints.cc", 242 | "entrypoints/quick/quick_lock_entrypoints.cc", 243 | "entrypoints/quick/quick_math_entrypoints.cc", 244 | "entrypoints/quick/quick_thread_entrypoints.cc", 245 | "entrypoints/quick/quick_throw_entrypoints.cc", 246 | "entrypoints/quick/quick_trampoline_entrypoints.cc", 247 | ], 248 | 249 | arch: { 250 | arm: { 251 | srcs: [ 252 | "interpreter/mterp/mterp.cc", 253 | ":libart_mterp.arm", 254 | "arch/arm/context_arm.cc", 255 | "arch/arm/entrypoints_init_arm.cc", 256 | "arch/arm/instruction_set_features_assembly_tests.S", 257 | "arch/arm/jni_entrypoints_arm.S", 258 | "arch/arm/memcmp16_arm.S", 259 | "arch/arm/quick_entrypoints_arm.S", 260 | "arch/arm/quick_entrypoints_cc_arm.cc", 261 | "arch/arm/thread_arm.cc", 262 | "arch/arm/fault_handler_arm.cc", 263 | ], 264 | }, 265 | arm64: { 266 | srcs: [ 267 | "interpreter/mterp/mterp.cc", 268 | ":libart_mterp.arm64", 269 | "arch/arm64/context_arm64.cc", 270 | "arch/arm64/entrypoints_init_arm64.cc", 271 | "arch/arm64/jni_entrypoints_arm64.S", 272 | "arch/arm64/memcmp16_arm64.S", 273 | "arch/arm64/quick_entrypoints_arm64.S", 274 | "arch/arm64/thread_arm64.cc", 275 | "monitor_pool.cc", 276 | "arch/arm64/fault_handler_arm64.cc", 277 | ], 278 | }, 279 | x86: { 280 | srcs: [ 281 | "interpreter/mterp/mterp.cc", 282 | ":libart_mterp.x86", 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 | }, 292 | x86_64: { 293 | srcs: [ 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 | "interpreter/mterp/mterp.cc", 297 | ":libart_mterp.x86_64", 298 | "arch/x86_64/context_x86_64.cc", 299 | "arch/x86_64/entrypoints_init_x86_64.cc", 300 | "arch/x86_64/jni_entrypoints_x86_64.S", 301 | "arch/x86_64/memcmp16_x86_64.S", 302 | "arch/x86_64/quick_entrypoints_x86_64.S", 303 | "arch/x86_64/thread_x86_64.cc", 304 | "monitor_pool.cc", 305 | "arch/x86/fault_handler_x86.cc", 306 | ], 307 | }, 308 | mips: { 309 | srcs: [ 310 | "interpreter/mterp/mterp.cc", 311 | ":libart_mterp.mips", 312 | "arch/mips/context_mips.cc", 313 | "arch/mips/entrypoints_init_mips.cc", 314 | "arch/mips/jni_entrypoints_mips.S", 315 | "arch/mips/memcmp16_mips.S", 316 | "arch/mips/quick_entrypoints_mips.S", 317 | "arch/mips/thread_mips.cc", 318 | "arch/mips/fault_handler_mips.cc", 319 | ], 320 | }, 321 | mips64: { 322 | srcs: [ 323 | "interpreter/mterp/mterp.cc", 324 | ":libart_mterp.mips64", 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 | }, 335 | }, 336 | target: { 337 | android: { 338 | srcs: [ 339 | "jdwp/jdwp_adb.cc", 340 | "monitor_android.cc", 341 | "runtime_android.cc", 342 | "thread_android.cc", 343 | ], 344 | shared_libs: [ 345 | "libdl_android", 346 | ], 347 | static_libs: [ 348 | "libz", // For adler32. 349 | ], 350 | cflags: [ 351 | // ART is allowed to link to libicuuc directly 352 | // since they are in the same module 353 | "-DANDROID_LINK_SHARED_ICU4C", 354 | "-Wno-error", 355 | "-DART_USE_CXX_INTERPRETER=1" 356 | ], 357 | }, 358 | android_arm: { 359 | ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS, 360 | }, 361 | android_arm64: { 362 | ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS, 363 | }, 364 | android_x86: { 365 | ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS, 366 | }, 367 | android_x86_64: { 368 | ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS, 369 | }, 370 | host: { 371 | srcs: [ 372 | "monitor_linux.cc", 373 | "runtime_linux.cc", 374 | "thread_linux.cc", 375 | ], 376 | shared_libs: [ 377 | "libz", // For adler32. 378 | ], 379 | }, 380 | }, 381 | cflags: ["-DBUILDING_LIBART=1"], 382 | generated_sources: ["art_operator_srcs"], 383 | // asm_support_gen.h (used by asm_support.h) is generated with cpp-define-generator 384 | generated_headers: ["cpp-define-generator-asm-support"], 385 | // export our headers so the libart-gtest targets can use it as well. 386 | export_generated_headers: ["cpp-define-generator-asm-support"], 387 | include_dirs: [ 388 | "art/sigchainlib", 389 | "external/zlib", 390 | ], 391 | header_libs: [ 392 | "art_cmdlineparser_headers", 393 | "cpp-define-generator-definitions", 394 | "libicuuc_headers", 395 | "libnativehelper_header_only", 396 | "jni_platform_headers", 397 | ], 398 | shared_libs: [ 399 | "libartpalette", 400 | "libnativebridge", 401 | "libnativeloader", 402 | "libbacktrace", 403 | "liblog", 404 | // For common macros. 405 | "libbase", 406 | ], 407 | static: { 408 | static_libs: ["libsigchain_dummy"], 409 | }, 410 | shared: { 411 | shared_libs: ["libsigchain"], 412 | }, 413 | export_include_dirs: ["."], 414 | // ART's macros.h depends on libbase's macros.h. 415 | // Note: runtime_options.h depends on cmdline. But we don't really want to export this 416 | // generically. dex2oat takes care of it itself. 417 | export_shared_lib_headers: ["libbase"], 418 | } 419 | 420 | libart_static_cc_defaults { 421 | name: "libart_static_base_defaults", 422 | static_libs: [ 423 | "libartpalette", 424 | "libbacktrace", 425 | "libbase", 426 | "libdexfile_external", // libunwindstack dependency 427 | "libdexfile_support", // libunwindstack dependency 428 | "liblog", 429 | "libnativebridge", 430 | "libnativeloader", 431 | "libsigchain_dummy", 432 | "libunwindstack", 433 | "libz", 434 | ], 435 | } 436 | 437 | cc_defaults { 438 | name: "libart_static_defaults", 439 | defaults: [ 440 | "libart_static_base_defaults", 441 | "libartbase_static_defaults", 442 | "libdexfile_static_defaults", 443 | "libprofile_static_defaults", 444 | ], 445 | static_libs: [ 446 | "libart", 447 | "libelffile", 448 | ], 449 | } 450 | 451 | cc_defaults { 452 | name: "libartd_static_defaults", 453 | defaults: [ 454 | "libart_static_base_defaults", 455 | "libartbased_static_defaults", 456 | "libdexfiled_static_defaults", 457 | "libprofiled_static_defaults", 458 | ], 459 | static_libs: [ 460 | "libartd", 461 | "libelffiled", 462 | ], 463 | } 464 | 465 | gensrcs { 466 | name: "art_operator_srcs", 467 | cmd: "$(location generate_operator_out) art/runtime $(in) > $(out)", 468 | tools: ["generate_operator_out"], 469 | srcs: [ 470 | "base/callee_save_type.h", 471 | "base/locks.h", 472 | "class_loader_context.h", 473 | "class_status.h", 474 | "debugger.h", 475 | "gc_root.h", 476 | "gc/allocator_type.h", 477 | "gc/allocator/rosalloc.h", 478 | "gc/collector_type.h", 479 | "gc/collector/gc_type.h", 480 | "gc/heap.h", 481 | "gc/space/region_space.h", 482 | "gc/space/space.h", 483 | "gc/weak_root_state.h", 484 | "image.h", 485 | "instrumentation.h", 486 | "indirect_reference_table.h", 487 | "jdwp_provider.h", 488 | "jdwp/jdwp.h", 489 | "jdwp/jdwp_constants.h", 490 | "lock_word.h", 491 | "oat.h", 492 | "object_callbacks.h", 493 | "process_state.h", 494 | "stack.h", 495 | "suspend_reason.h", 496 | "thread.h", 497 | "thread_state.h", 498 | "ti/agent.h", 499 | "trace.h", 500 | "verifier/verifier_enums.h", 501 | ], 502 | output_extension: "operator_out.cc", 503 | } 504 | 505 | // We always build dex2oat and dependencies, even if the host build is otherwise disabled, since 506 | // they are used to cross compile for the target. 507 | 508 | art_cc_library { 509 | name: "libart", 510 | defaults: ["libart_defaults"], 511 | // Leave the symbols in the shared library so that stack unwinders can 512 | // produce meaningful name resolution. 513 | strip: { 514 | keep_symbols: true, 515 | }, 516 | whole_static_libs: [ 517 | ], 518 | static_libs: [ 519 | "libelffile", 520 | ], 521 | shared_libs: [ 522 | "libartbase", 523 | "libdexfile", 524 | "libprofile", 525 | ], 526 | export_shared_lib_headers: [ 527 | "libdexfile", 528 | ], 529 | target: { 530 | android: { 531 | lto: { 532 | thin: true, 533 | }, 534 | }, 535 | }, 536 | } 537 | 538 | art_cc_library { 539 | name: "libartd", 540 | defaults: [ 541 | "art_debug_defaults", 542 | "libart_defaults", 543 | ], 544 | whole_static_libs: [ 545 | ], 546 | static_libs: [ 547 | "libelffiled", 548 | ], 549 | shared_libs: [ 550 | "libartbased", 551 | "libdexfiled", 552 | "libprofiled", 553 | ], 554 | export_shared_lib_headers: [ 555 | "libdexfiled", 556 | ], 557 | } 558 | 559 | art_cc_library { 560 | name: "libart-runtime-gtest", 561 | defaults: ["libart-gtest-defaults"], 562 | srcs: [ 563 | "common_runtime_test.cc", 564 | "dexopt_test.cc", 565 | ], 566 | shared_libs: [ 567 | "libartd", 568 | "libartbase-art-gtest", 569 | "libbase", 570 | "libbacktrace", 571 | ], 572 | header_libs: [ 573 | "libnativehelper_header_only", 574 | ], 575 | } 576 | 577 | art_cc_test { 578 | name: "art_runtime_tests", 579 | defaults: [ 580 | "art_gtest_defaults", 581 | ], 582 | srcs: [ 583 | "arch/arch_test.cc", 584 | "arch/instruction_set_features_test.cc", 585 | "arch/memcmp16_test.cc", 586 | "arch/stub_test.cc", 587 | "arch/arm/instruction_set_features_arm_test.cc", 588 | "arch/arm64/instruction_set_features_arm64_test.cc", 589 | "arch/mips/instruction_set_features_mips_test.cc", 590 | "arch/mips64/instruction_set_features_mips64_test.cc", 591 | "arch/x86/instruction_set_features_x86_test.cc", 592 | "arch/x86_64/instruction_set_features_x86_64_test.cc", 593 | "barrier_test.cc", 594 | "base/mutex_test.cc", 595 | "base/timing_logger_test.cc", 596 | "cha_test.cc", 597 | "class_linker_test.cc", 598 | "class_loader_context_test.cc", 599 | "class_table_test.cc", 600 | "compiler_filter_test.cc", 601 | "entrypoints/math_entrypoints_test.cc", 602 | "entrypoints/quick/quick_trampoline_entrypoints_test.cc", 603 | "entrypoints_order_test.cc", 604 | "exec_utils_test.cc", 605 | "gc/accounting/card_table_test.cc", 606 | "gc/accounting/mod_union_table_test.cc", 607 | "gc/accounting/space_bitmap_test.cc", 608 | "gc/collector/immune_spaces_test.cc", 609 | "gc/heap_test.cc", 610 | "gc/heap_verification_test.cc", 611 | "gc/reference_queue_test.cc", 612 | "gc/space/dlmalloc_space_static_test.cc", 613 | "gc/space/dlmalloc_space_random_test.cc", 614 | "gc/space/image_space_test.cc", 615 | "gc/space/large_object_space_test.cc", 616 | "gc/space/rosalloc_space_static_test.cc", 617 | "gc/space/rosalloc_space_random_test.cc", 618 | "gc/space/space_create_test.cc", 619 | "gc/system_weak_test.cc", 620 | "gc/task_processor_test.cc", 621 | "gtest_test.cc", 622 | "handle_scope_test.cc", 623 | "hidden_api_test.cc", 624 | "imtable_test.cc", 625 | "indirect_reference_table_test.cc", 626 | "instrumentation_test.cc", 627 | "intern_table_test.cc", 628 | "interpreter/safe_math_test.cc", 629 | "interpreter/unstarted_runtime_test.cc", 630 | "jdwp/jdwp_options_test.cc", 631 | "jit/profiling_info_test.cc", 632 | "jni/java_vm_ext_test.cc", 633 | "jni/jni_internal_test.cc", 634 | "method_handles_test.cc", 635 | "mirror/dex_cache_test.cc", 636 | "mirror/method_type_test.cc", 637 | "mirror/object_test.cc", 638 | "mirror/var_handle_test.cc", 639 | "monitor_pool_test.cc", 640 | "monitor_test.cc", 641 | "oat_file_test.cc", 642 | "oat_file_assistant_test.cc", 643 | "parsed_options_test.cc", 644 | "prebuilt_tools_test.cc", 645 | "proxy_test.cc", 646 | "reference_table_test.cc", 647 | "runtime_callbacks_test.cc", 648 | "runtime_test.cc", 649 | "subtype_check_info_test.cc", 650 | "subtype_check_test.cc", 651 | "thread_pool_test.cc", 652 | "transaction_test.cc", 653 | "two_runtimes_test.cc", 654 | "vdex_file_test.cc", 655 | "verifier/method_verifier_test.cc", 656 | "verifier/reg_type_test.cc", 657 | ], 658 | shared_libs: [ 659 | "libbacktrace", 660 | ], 661 | header_libs: [ 662 | "art_cmdlineparser_headers", // For parsed_options_test. 663 | ], 664 | include_dirs: [ 665 | "external/zlib", 666 | ], 667 | } 668 | 669 | art_cc_test { 670 | name: "art_runtime_compiler_tests", 671 | defaults: [ 672 | "art_gtest_defaults", 673 | ], 674 | srcs: [ 675 | "reflection_test.cc", 676 | "module_exclusion_test.cc", 677 | ], 678 | shared_libs: [ 679 | "libartd-compiler", 680 | "libvixld", 681 | ], 682 | } 683 | 684 | cc_library_headers { 685 | name: "libart_runtime_headers", 686 | host_supported: true, 687 | export_include_dirs: ["."], 688 | } 689 | 690 | genrule { 691 | name: "libart_mterp.arm", 692 | out: ["mterp_arm.S"], 693 | srcs: ["interpreter/mterp/arm/*.S"], 694 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 695 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 696 | } 697 | 698 | genrule { 699 | name: "libart_mterp.arm64", 700 | out: ["mterp_arm64.S"], 701 | srcs: ["interpreter/mterp/arm64/*.S"], 702 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 703 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 704 | } 705 | 706 | genrule { 707 | name: "libart_mterp.mips", 708 | out: ["mterp_mips.S"], 709 | srcs: ["interpreter/mterp/mips/*.S"], 710 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 711 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 712 | } 713 | 714 | genrule { 715 | name: "libart_mterp.mips64", 716 | out: ["mterp_mips64.S"], 717 | srcs: ["interpreter/mterp/mips64/*.S"], 718 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 719 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 720 | } 721 | 722 | genrule { 723 | name: "libart_mterp.x86", 724 | out: ["mterp_x86.S"], 725 | srcs: ["interpreter/mterp/x86/*.S"], 726 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 727 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 728 | } 729 | 730 | genrule { 731 | name: "libart_mterp.x86_64", 732 | out: ["mterp_x86_64.S"], 733 | srcs: ["interpreter/mterp/x86_64/*.S"], 734 | tool_files: ["interpreter/mterp/gen_mterp.py", "interpreter/mterp/common/gen_setup.py"], 735 | cmd: "$(location interpreter/mterp/gen_mterp.py) $(out) $(in)", 736 | } 737 | -------------------------------------------------------------------------------- /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 20 | 21 | #include "android-base/stringprintf.h" 22 | 23 | #include "arch/context.h" 24 | #include "art_method-inl.h" 25 | #include "class_linker-inl.h" 26 | #include "class_root.h" 27 | #include "debugger.h" 28 | #include "dex/class_accessor-inl.h" 29 | #include "dex/descriptors_names.h" 30 | #include "dex/dex_file-inl.h" 31 | #include "dex/dex_file_exception_helpers.h" 32 | #include "dex/dex_instruction.h" 33 | #include "dex/signature-inl.h" 34 | #include "entrypoints/runtime_asm_entrypoints.h" 35 | #include "gc/accounting/card_table-inl.h" 36 | #include "hidden_api.h" 37 | #include "interpreter/interpreter.h" 38 | #include "jit/jit.h" 39 | #include "jit/jit_code_cache.h" 40 | #include "jit/profiling_info.h" 41 | #include "jni/jni_internal.h" 42 | #include "mirror/class-inl.h" 43 | #include "mirror/class_ext-inl.h" 44 | #include "mirror/executable.h" 45 | #include "mirror/object-inl.h" 46 | #include "mirror/object_array-inl.h" 47 | #include "mirror/string.h" 48 | #include "oat_file-inl.h" 49 | #include "quicken_info.h" 50 | #include "runtime_callbacks.h" 51 | #include "scoped_thread_state_change-inl.h" 52 | #include "vdex_file.h" 53 | //added code 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include "runtime.h" 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | 79 | #define gettidv1() syscall(__NR_gettid) 80 | #define LOG_TAG "ActivityThread" 81 | #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 82 | //add end 83 | 84 | namespace art { 85 | 86 | using android::base::StringPrintf; 87 | 88 | extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, 89 | const char*); 90 | extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, 91 | const char*); 92 | 93 | // Enforce that we he have the right index for runtime methods. 94 | static_assert(ArtMethod::kRuntimeMethodDexMethodIndex == dex::kDexNoIndex, 95 | "Wrong runtime-method dex method index"); 96 | 97 | 98 | 99 | ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) { 100 | if (LIKELY(!IsDefault())) { 101 | return this; 102 | } else { 103 | ObjPtr declaring_class = GetDeclaringClass(); 104 | DCHECK(declaring_class->IsInterface()); 105 | ArtMethod* ret = declaring_class->FindInterfaceMethod(GetDexCache(), 106 | GetDexMethodIndex(), 107 | pointer_size); 108 | DCHECK(ret != nullptr); 109 | return ret; 110 | } 111 | } 112 | 113 | //add 114 | uint8_t* codeitem_end(const uint8_t **pData) 115 | { 116 | uint32_t num_of_list = DecodeUnsignedLeb128(pData); 117 | for (;num_of_list>0;num_of_list--) { 118 | int32_t num_of_handlers=DecodeSignedLeb128(pData); 119 | int num=num_of_handlers; 120 | if (num_of_handlers<=0) { 121 | num=-num_of_handlers; 122 | } 123 | for (; num > 0; num--) { 124 | DecodeUnsignedLeb128(pData); 125 | DecodeUnsignedLeb128(pData); 126 | } 127 | if (num_of_handlers<=0) { 128 | DecodeUnsignedLeb128(pData); 129 | } 130 | } 131 | return (uint8_t*)(*pData); 132 | } 133 | 134 | 135 | 136 | extern "C" char *base64_encode(char *str,long str_len,long* outlen){ 137 | long len; 138 | char *res; 139 | int i,j; 140 | const char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 141 | if(str_len % 3 == 0) 142 | len=str_len/3*4; 143 | else 144 | len=(str_len/3+1)*4; 145 | 146 | res=(char*)malloc(sizeof(char)*(len+1)); 147 | res[len]='\0'; 148 | *outlen=len; 149 | for(i=0,j=0;i>2]; 152 | res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; 153 | res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; 154 | res[i+3]=base64_table[str[j+2]&0x3f]; 155 | } 156 | 157 | switch(str_len % 3) 158 | { 159 | case 1: 160 | res[i-2]='='; 161 | res[i-1]='='; 162 | break; 163 | case 2: 164 | res[i-1]='='; 165 | break; 166 | } 167 | 168 | return res; 169 | } 170 | //在函数即将调用解释器执行前进行dump。 171 | extern "C" void dumpdexfilebyExecute(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) { 172 | char *dexfilepath=(char*)malloc(sizeof(char)*1000); 173 | if(dexfilepath==nullptr) 174 | { 175 | LOG(ERROR)<< "fartext ArtMethod::dumpdexfilebyArtMethod,methodname:"<PrettyMethod().c_str()<<"malloc 1000 byte failed"; 176 | return; 177 | } 178 | int result=0; 179 | int fcmdline =-1; 180 | char szCmdline[64]= {0}; 181 | char szProcName[256] = {0}; 182 | int procid = getpid(); 183 | sprintf(szCmdline,"/proc/%d/cmdline", procid); 184 | fcmdline = open(szCmdline, O_RDONLY,0644); 185 | if(fcmdline >0) 186 | { 187 | result=read(fcmdline, szProcName,256); 188 | if(result<0) 189 | { 190 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,open cmdline file error"; 191 | } 192 | close(fcmdline); 193 | 194 | } 195 | 196 | if(szProcName[0]) 197 | { 198 | 199 | const DexFile* dex_file = artmethod->GetDexFile(); 200 | const uint8_t* begin_=dex_file->Begin(); // Start of data. 201 | size_t size_=dex_file->Size(); // Length of data. 202 | 203 | memset(dexfilepath,0,1000); 204 | int size_int_=(int)size_; 205 | 206 | memset(dexfilepath,0,1000); 207 | sprintf(dexfilepath,"%s","/sdcard/fext"); 208 | mkdir(dexfilepath,0777); 209 | 210 | memset(dexfilepath,0,1000); 211 | sprintf(dexfilepath,"/sdcard/fext/%s",szProcName); 212 | mkdir(dexfilepath,0777); 213 | 214 | memset(dexfilepath,0,1000); 215 | sprintf(dexfilepath,"/sdcard/fext/%s/%d_dexfile_execute.dex",szProcName,size_int_); 216 | int dexfilefp=open(dexfilepath,O_RDONLY,0666); 217 | if(dexfilefp>0){ 218 | close(dexfilefp); 219 | dexfilefp=0; 220 | 221 | }else{ 222 | int fp=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666); 223 | if(fp>0) 224 | { 225 | result=write(fp,(void*)begin_,size_); 226 | if(result<0) 227 | { 228 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,open dexfilepath error"; 229 | } 230 | fsync(fp); 231 | close(fp); 232 | memset(dexfilepath,0,1000); 233 | sprintf(dexfilepath,"/sdcard/fext/%s/%d_classlist_execute.txt",szProcName,size_int_); 234 | int classlistfile=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666); 235 | if(classlistfile>0) 236 | { 237 | for (size_t ii= 0; ii< dex_file->NumClassDefs(); ++ii) 238 | { 239 | const dex::ClassDef& class_def = dex_file->GetClassDef(ii); 240 | const char* descriptor = dex_file->GetClassDescriptor(class_def); 241 | result=write(classlistfile,(void*)descriptor,strlen(descriptor)); 242 | if(result<0) 243 | { 244 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"; 245 | 246 | } 247 | const char* temp="\n"; 248 | result=write(classlistfile,(void*)temp,1); 249 | if(result<0) 250 | { 251 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"; 252 | 253 | } 254 | } 255 | fsync(classlistfile); 256 | close(classlistfile); 257 | 258 | } 259 | } 260 | 261 | 262 | } 263 | 264 | 265 | } 266 | 267 | if(dexfilepath!=nullptr) 268 | { 269 | free(dexfilepath); 270 | dexfilepath=nullptr; 271 | } 272 | 273 | } 274 | 275 | extern "C" bool ShouldUnpack() { 276 | int result=0; 277 | int fcmdline =-1; 278 | char szCmdline[64]= {0}; 279 | char szProcName[256] = {0}; 280 | int procid = getpid(); 281 | sprintf(szCmdline,"/proc/%d/cmdline", procid); 282 | fcmdline = open(szCmdline, O_RDONLY,0644); 283 | if(fcmdline >0) 284 | { 285 | result=read(fcmdline, szProcName,256); 286 | if(result<0) 287 | { 288 | LOG(ERROR) << "fartext ArtMethod::ShouldUnpack,open cmdline file file error"; 289 | } 290 | close(fcmdline); 291 | } 292 | if(szProcName[0]){ 293 | const char* UNPACK_CONFIG = "/data/local/tmp/fext.config"; 294 | std::ifstream config(UNPACK_CONFIG); 295 | std::string line; 296 | if(config) { 297 | while (std::getline(config, line)) { 298 | std::string package_name = line.substr(0, line.find(':')); 299 | if (strstr(package_name.c_str(),szProcName)) { 300 | return true; 301 | } 302 | } 303 | } 304 | return false; 305 | } 306 | return false; 307 | 308 | } 309 | 310 | //主动调用函数的dump处理 311 | extern "C" void dumpArtMethod(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) { 312 | LOG(ERROR) << "fartext ArtMethod::dumpArtMethod enter "<PrettyMethod().c_str(); 313 | char *dexfilepath=(char*)malloc(sizeof(char)*1000); 314 | if(dexfilepath==nullptr) 315 | { 316 | LOG(ERROR) << "fartext ArtMethod::dumpArtMethodinvoked,methodname:"<PrettyMethod().c_str()<<"malloc 1000 byte failed"; 317 | return; 318 | } 319 | int result=0; 320 | int fcmdline =-1; 321 | char szCmdline[64]= {0}; 322 | char szProcName[256] = {0}; 323 | int procid = getpid(); 324 | sprintf(szCmdline,"/proc/%d/cmdline", procid); 325 | fcmdline = open(szCmdline, O_RDONLY,0644); 326 | if(fcmdline >0) 327 | { 328 | result=read(fcmdline, szProcName,256); 329 | if(result<0) 330 | { 331 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,open cmdline file file error"; 332 | } 333 | close(fcmdline); 334 | } 335 | 336 | if(szProcName[0]) 337 | { 338 | const DexFile* dex_file = artmethod->GetDexFile(); 339 | const uint8_t* begin_=dex_file->Begin(); // Start of data. 340 | size_t size_=dex_file->Size(); // Length of data. 341 | 342 | memset(dexfilepath,0,1000); 343 | int size_int_=(int)size_; 344 | 345 | memset(dexfilepath,0,1000); 346 | sprintf(dexfilepath,"%s","/sdcard/fext"); 347 | mkdir(dexfilepath,0777); 348 | 349 | memset(dexfilepath,0,1000); 350 | sprintf(dexfilepath,"/sdcard/fext/%s",szProcName); 351 | mkdir(dexfilepath,0777); 352 | 353 | memset(dexfilepath,0,1000); 354 | sprintf(dexfilepath,"/sdcard/fext/%s/%d_dexfile.dex",szProcName,size_int_); 355 | int dexfilefp=open(dexfilepath,O_RDONLY,0666); 356 | if(dexfilefp>0){ 357 | close(dexfilefp); 358 | dexfilefp=0; 359 | 360 | }else{ 361 | int fp=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666); 362 | if(fp>0) 363 | { 364 | result=write(fp,(void*)begin_,size_); 365 | if(result<0) 366 | { 367 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,open dexfilepath file error"; 368 | 369 | } 370 | fsync(fp); 371 | close(fp); 372 | memset(dexfilepath,0,1000); 373 | sprintf(dexfilepath,"/sdcard/fext/%s/%d_classlist.txt",szProcName,size_int_); 374 | int classlistfile=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666); 375 | if(classlistfile>0) 376 | { 377 | for (size_t ii= 0; ii< dex_file->NumClassDefs(); ++ii) 378 | { 379 | const dex::ClassDef& class_def = dex_file->GetClassDef(ii); 380 | const char* descriptor = dex_file->GetClassDescriptor(class_def); 381 | result=write(classlistfile,(void*)descriptor,strlen(descriptor)); 382 | if(result<0) 383 | { 384 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"; 385 | 386 | } 387 | const char* temp="\n"; 388 | result=write(classlistfile,(void*)temp,1); 389 | if(result<0) 390 | { 391 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"; 392 | 393 | } 394 | } 395 | fsync(classlistfile); 396 | close(classlistfile); 397 | 398 | } 399 | } 400 | 401 | 402 | } 403 | 404 | const dex::CodeItem* code_item = artmethod->GetCodeItem(); 405 | const DexFile* dex_=artmethod->GetDexFile(); 406 | CodeItemDataAccessor accessor(*dex_, dex_->GetCodeItem(artmethod->GetCodeItemOffset())); 407 | if (LIKELY(code_item != nullptr)) 408 | { 409 | 410 | int code_item_len = 0; 411 | uint8_t *item=(uint8_t *) code_item; 412 | if (accessor.TriesSize()>0) { 413 | const uint8_t *handler_data = accessor.GetCatchHandlerData(); 414 | uint8_t * tail = codeitem_end(&handler_data); 415 | code_item_len = (int)(tail - item); 416 | }else{ 417 | code_item_len = 16+accessor.InsnsSizeInCodeUnits()*2; 418 | } 419 | memset(dexfilepath,0,1000); 420 | int size_int=(int)dex_file->Size(); 421 | uint32_t method_idx=artmethod->GetDexMethodIndex(); 422 | sprintf(dexfilepath,"/sdcard/fext/%s/%d_ins_%d.bin",szProcName,size_int,(int)gettidv1()); 423 | int fp2=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666); 424 | if(fp2>0){ 425 | lseek(fp2,0,SEEK_END); 426 | memset(dexfilepath,0,1000); 427 | int offset=(int)(item - begin_); 428 | sprintf(dexfilepath,"{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:",artmethod->PrettyMethod().c_str(),method_idx,offset,code_item_len); 429 | int contentlength=0; 430 | while(dexfilepath[contentlength]!=0) contentlength++; 431 | result=write(fp2,(void*)dexfilepath,contentlength); 432 | if(result<0) 433 | { 434 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write ins file error"; 435 | 436 | } 437 | long outlen=0; 438 | char* base64result=base64_encode((char*)item,(long)code_item_len,&outlen); 439 | result=write(fp2,base64result,outlen); 440 | if(result<0) 441 | { 442 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write ins file error"; 443 | 444 | } 445 | result=write(fp2,"};",2); 446 | if(result<0) 447 | { 448 | LOG(ERROR) << "fartext ArtMethod::dumpdexfilebyArtMethod,write ins file error"; 449 | 450 | } 451 | fsync(fp2); 452 | close(fp2); 453 | if(base64result!=nullptr){ 454 | free(base64result); 455 | base64result=nullptr; 456 | } 457 | } 458 | 459 | } 460 | 461 | 462 | } 463 | 464 | if(dexfilepath!=nullptr) 465 | { 466 | free(dexfilepath); 467 | dexfilepath=nullptr; 468 | } 469 | LOG(ERROR) << "fartext ArtMethod::dumpArtMethod over "<PrettyMethod().c_str(); 470 | } 471 | extern "C" void fartextInvoke(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) { 472 | if(artmethod->IsNative()||artmethod->IsAbstract()){ 473 | return; 474 | } 475 | JValue result; 476 | Thread *self=Thread::Current(); 477 | uint32_t temp[100]={0}; 478 | uint32_t* args=temp; 479 | uint32_t args_size = (uint32_t)ArtMethod::NumArgRegisters(artmethod->GetShorty()); 480 | if (!artmethod->IsStatic()) { 481 | args_size += 1; 482 | } 483 | result.SetI(111111); 484 | LOG(ERROR) << "fartext fartextInvoke"; 485 | artmethod->Invoke(self, args, args_size, &result,artmethod->GetShorty()); 486 | } 487 | 488 | //addend 489 | 490 | ArtMethod* ArtMethod::GetNonObsoleteMethod() { 491 | if (LIKELY(!IsObsolete())) { 492 | return this; 493 | } 494 | DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); 495 | if (IsDirect()) { 496 | return &GetDeclaringClass()->GetDirectMethodsSlice(kRuntimePointerSize)[GetMethodIndex()]; 497 | } else { 498 | return GetDeclaringClass()->GetVTableEntry(GetMethodIndex(), kRuntimePointerSize); 499 | } 500 | } 501 | 502 | ArtMethod* ArtMethod::GetSingleImplementation(PointerSize pointer_size) { 503 | if (!IsAbstract()) { 504 | // A non-abstract's single implementation is itself. 505 | return this; 506 | } 507 | return reinterpret_cast(GetDataPtrSize(pointer_size)); 508 | } 509 | 510 | ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, 511 | jobject jlr_method) { 512 | ObjPtr executable = soa.Decode(jlr_method); 513 | DCHECK(executable != nullptr); 514 | return executable->GetArtMethod(); 515 | } 516 | 517 | ObjPtr ArtMethod::GetObsoleteDexCache() { 518 | DCHECK(!Runtime::Current()->IsAotCompiler()) << PrettyMethod(); 519 | DCHECK(IsObsolete()); 520 | ObjPtr ext(GetDeclaringClass()->GetExtData()); 521 | CHECK(!ext.IsNull()); 522 | ObjPtr obsolete_methods(ext->GetObsoleteMethods()); 523 | CHECK(!obsolete_methods.IsNull()); 524 | DCHECK(ext->GetObsoleteDexCaches() != nullptr); 525 | int32_t len = obsolete_methods->GetLength(); 526 | DCHECK_EQ(len, ext->GetObsoleteDexCaches()->GetLength()); 527 | // Using kRuntimePointerSize (instead of using the image's pointer size) is fine since images 528 | // should never have obsolete methods in them so they should always be the same. 529 | PointerSize pointer_size = kRuntimePointerSize; 530 | DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); 531 | for (int32_t i = 0; i < len; i++) { 532 | if (this == obsolete_methods->GetElementPtrSize(i, pointer_size)) { 533 | return ext->GetObsoleteDexCaches()->Get(i); 534 | } 535 | } 536 | LOG(FATAL) << "This method does not appear in the obsolete map of its class!"; 537 | UNREACHABLE(); 538 | } 539 | 540 | uint16_t ArtMethod::FindObsoleteDexClassDefIndex() { 541 | DCHECK(!Runtime::Current()->IsAotCompiler()) << PrettyMethod(); 542 | DCHECK(IsObsolete()); 543 | const DexFile* dex_file = GetDexFile(); 544 | const dex::TypeIndex declaring_class_type = dex_file->GetMethodId(GetDexMethodIndex()).class_idx_; 545 | const dex::ClassDef* class_def = dex_file->FindClassDef(declaring_class_type); 546 | CHECK(class_def != nullptr); 547 | return dex_file->GetIndexForClassDef(*class_def); 548 | } 549 | 550 | void ArtMethod::ThrowInvocationTimeError() { 551 | DCHECK(!IsInvokable()); 552 | // NOTE: IsDefaultConflicting must be first since the actual method might or might not be abstract 553 | // due to the way we select it. 554 | if (IsDefaultConflicting()) { 555 | ThrowIncompatibleClassChangeErrorForMethodConflict(this); 556 | } else { 557 | DCHECK(IsAbstract()); 558 | ThrowAbstractMethodError(this); 559 | } 560 | } 561 | 562 | InvokeType ArtMethod::GetInvokeType() { 563 | // TODO: kSuper? 564 | if (IsStatic()) { 565 | return kStatic; 566 | } else if (GetDeclaringClass()->IsInterface()) { 567 | return kInterface; 568 | } else if (IsDirect()) { 569 | return kDirect; 570 | } else if (IsPolymorphicSignature()) { 571 | return kPolymorphic; 572 | } else { 573 | return kVirtual; 574 | } 575 | } 576 | 577 | size_t ArtMethod::NumArgRegisters(const char* shorty) { 578 | CHECK_NE(shorty[0], '\0'); 579 | uint32_t num_registers = 0; 580 | for (const char* s = shorty + 1; *s != '\0'; ++s) { 581 | if (*s == 'D' || *s == 'J') { 582 | num_registers += 2; 583 | } else { 584 | num_registers += 1; 585 | } 586 | } 587 | return num_registers; 588 | } 589 | 590 | bool ArtMethod::HasSameNameAndSignature(ArtMethod* other) { 591 | ScopedAssertNoThreadSuspension ants("HasSameNameAndSignature"); 592 | const DexFile* dex_file = GetDexFile(); 593 | const dex::MethodId& mid = dex_file->GetMethodId(GetDexMethodIndex()); 594 | if (GetDexCache() == other->GetDexCache()) { 595 | const dex::MethodId& mid2 = dex_file->GetMethodId(other->GetDexMethodIndex()); 596 | return mid.name_idx_ == mid2.name_idx_ && mid.proto_idx_ == mid2.proto_idx_; 597 | } 598 | const DexFile* dex_file2 = other->GetDexFile(); 599 | const dex::MethodId& mid2 = dex_file2->GetMethodId(other->GetDexMethodIndex()); 600 | if (!DexFile::StringEquals(dex_file, mid.name_idx_, dex_file2, mid2.name_idx_)) { 601 | return false; // Name mismatch. 602 | } 603 | return dex_file->GetMethodSignature(mid) == dex_file2->GetMethodSignature(mid2); 604 | } 605 | 606 | ArtMethod* ArtMethod::FindOverriddenMethod(PointerSize pointer_size) { 607 | if (IsStatic()) { 608 | return nullptr; 609 | } 610 | ObjPtr declaring_class = GetDeclaringClass(); 611 | ObjPtr super_class = declaring_class->GetSuperClass(); 612 | uint16_t method_index = GetMethodIndex(); 613 | ArtMethod* result = nullptr; 614 | // Did this method override a super class method? If so load the result from the super class' 615 | // vtable 616 | if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) { 617 | result = super_class->GetVTableEntry(method_index, pointer_size); 618 | } else { 619 | // Method didn't override superclass method so search interfaces 620 | if (IsProxyMethod()) { 621 | result = GetInterfaceMethodIfProxy(pointer_size); 622 | DCHECK(result != nullptr); 623 | } else { 624 | ObjPtr iftable = GetDeclaringClass()->GetIfTable(); 625 | for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) { 626 | ObjPtr interface = iftable->GetInterface(i); 627 | for (ArtMethod& interface_method : interface->GetVirtualMethods(pointer_size)) { 628 | if (HasSameNameAndSignature(interface_method.GetInterfaceMethodIfProxy(pointer_size))) { 629 | result = &interface_method; 630 | break; 631 | } 632 | } 633 | } 634 | } 635 | } 636 | DCHECK(result == nullptr || 637 | GetInterfaceMethodIfProxy(pointer_size)->HasSameNameAndSignature( 638 | result->GetInterfaceMethodIfProxy(pointer_size))); 639 | return result; 640 | } 641 | 642 | uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile, 643 | uint32_t name_and_signature_idx) { 644 | const DexFile* dexfile = GetDexFile(); 645 | const uint32_t dex_method_idx = GetDexMethodIndex(); 646 | const dex::MethodId& mid = dexfile->GetMethodId(dex_method_idx); 647 | const dex::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx); 648 | DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid)); 649 | DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid)); 650 | if (dexfile == &other_dexfile) { 651 | return dex_method_idx; 652 | } 653 | const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); 654 | const dex::TypeId* other_type_id = other_dexfile.FindTypeId(mid_declaring_class_descriptor); 655 | if (other_type_id != nullptr) { 656 | const dex::MethodId* other_mid = other_dexfile.FindMethodId( 657 | *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_), 658 | other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_)); 659 | if (other_mid != nullptr) { 660 | return other_dexfile.GetIndexForMethodId(*other_mid); 661 | } 662 | } 663 | return dex::kDexNoIndex; 664 | } 665 | 666 | uint32_t ArtMethod::FindCatchBlock(Handle exception_type, 667 | uint32_t dex_pc, bool* has_no_move_exception) { 668 | // Set aside the exception while we resolve its type. 669 | Thread* self = Thread::Current(); 670 | StackHandleScope<1> hs(self); 671 | Handle exception(hs.NewHandle(self->GetException())); 672 | self->ClearException(); 673 | // Default to handler not found. 674 | uint32_t found_dex_pc = dex::kDexNoIndex; 675 | // Iterate over the catch handlers associated with dex_pc. 676 | CodeItemDataAccessor accessor(DexInstructionData()); 677 | for (CatchHandlerIterator it(accessor, dex_pc); it.HasNext(); it.Next()) { 678 | dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex(); 679 | // Catch all case 680 | if (!iter_type_idx.IsValid()) { 681 | found_dex_pc = it.GetHandlerAddress(); 682 | break; 683 | } 684 | // Does this catch exception type apply? 685 | ObjPtr iter_exception_type = ResolveClassFromTypeIndex(iter_type_idx); 686 | if (UNLIKELY(iter_exception_type == nullptr)) { 687 | // Now have a NoClassDefFoundError as exception. Ignore in case the exception class was 688 | // removed by a pro-guard like tool. 689 | // Note: this is not RI behavior. RI would have failed when loading the class. 690 | self->ClearException(); 691 | // Delete any long jump context as this routine is called during a stack walk which will 692 | // release its in use context at the end. 693 | delete self->GetLongJumpContext(); 694 | LOG(WARNING) << "Unresolved exception class when finding catch block: " 695 | << DescriptorToDot(GetTypeDescriptorFromTypeIdx(iter_type_idx)); 696 | } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) { 697 | found_dex_pc = it.GetHandlerAddress(); 698 | break; 699 | } 700 | } 701 | if (found_dex_pc != dex::kDexNoIndex) { 702 | const Instruction& first_catch_instr = accessor.InstructionAt(found_dex_pc); 703 | *has_no_move_exception = (first_catch_instr.Opcode() != Instruction::MOVE_EXCEPTION); 704 | } 705 | // Put the exception back. 706 | if (exception != nullptr) { 707 | self->SetException(exception.Get()); 708 | } 709 | return found_dex_pc; 710 | } 711 | 712 | void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, 713 | const char* shorty) { 714 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) { 715 | ThrowStackOverflowError(self); 716 | return; 717 | } 718 | 719 | if (kIsDebugBuild) { 720 | self->AssertThreadSuspensionIsAllowable(); 721 | CHECK_EQ(kRunnable, self->GetState()); 722 | CHECK_STREQ(GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(), shorty); 723 | } 724 | 725 | // Push a transition back into managed code onto the linked list in thread. 726 | ManagedStack fragment; 727 | self->PushManagedStackFragment(&fragment); 728 | 729 | Runtime* runtime = Runtime::Current(); 730 | // Call the invoke stub, passing everything as arguments. 731 | // If the runtime is not yet started or it is required by the debugger, then perform the 732 | // Invocation by the interpreter, explicitly forcing interpretation over JIT to prevent 733 | // cycling around the various JIT/Interpreter methods that handle method invocation. 734 | 735 | //add 736 | 737 | if ((result!=nullptr && result->GetI()==111111)&&!IsNative()){ 738 | const dex::CodeItem* code_item =this->GetCodeItem(); 739 | if(LIKELY(code_item!=nullptr)){ 740 | 741 | if (IsStatic()) { 742 | LOG(ERROR) << "fartext artMethod::Invoke Static Method "<PrettyMethod().c_str(); 743 | art::interpreter::EnterInterpreterFromInvoke( 744 | self, this, nullptr, args, result, /*stay_in_interpreter=*/ true); 745 | }else{ 746 | LOG(ERROR) << "fartext artMethod::Invoke Method "<PrettyMethod().c_str(); 747 | art::interpreter::EnterInterpreterFromInvoke( 748 | self, this, nullptr, args + 1, result, /*stay_in_interpreter=*/ true); 749 | } 750 | self->PopManagedStackFragment(fragment); 751 | } 752 | return; 753 | } 754 | //add end 755 | if (UNLIKELY(!runtime->IsStarted() || 756 | (self->IsForceInterpreter() && !IsNative() && !IsProxyMethod() && IsInvokable()) || 757 | Dbg::IsForcedInterpreterNeededForCalling(self, this))) { 758 | 759 | if (IsStatic()) { 760 | art::interpreter::EnterInterpreterFromInvoke( 761 | self, this, nullptr, args, result, /*stay_in_interpreter=*/ true); 762 | } else { 763 | mirror::Object* receiver = 764 | reinterpret_cast*>(&args[0])->AsMirrorPtr(); 765 | art::interpreter::EnterInterpreterFromInvoke( 766 | self, this, receiver, args + 1, result, /*stay_in_interpreter=*/ true); 767 | } 768 | } else { 769 | if (result!=nullptr && result->GetI()==111111){ 770 | LOG(ERROR) << "fartext artMethod::Invoke return Native Method "<PrettyMethod().c_str(); 771 | return; 772 | } 773 | DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize); 774 | constexpr bool kLogInvocationStartAndReturn = false; 775 | bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr; 776 | if (LIKELY(have_quick_code)) { 777 | if (kLogInvocationStartAndReturn) { 778 | LOG(INFO) << StringPrintf( 779 | "Invoking '%s' quick code=%p static=%d", PrettyMethod().c_str(), 780 | GetEntryPointFromQuickCompiledCode(), static_cast(IsStatic() ? 1 : 0)); 781 | } 782 | 783 | // Ensure that we won't be accidentally calling quick compiled code when -Xint. 784 | if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) { 785 | CHECK(!runtime->UseJitCompilation()); 786 | const void* oat_quick_code = 787 | (IsNative() || !IsInvokable() || IsProxyMethod() || IsObsolete()) 788 | ? nullptr 789 | : GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()); 790 | CHECK(oat_quick_code == nullptr || oat_quick_code != GetEntryPointFromQuickCompiledCode()) 791 | << "Don't call compiled code when -Xint " << PrettyMethod(); 792 | } 793 | 794 | if (!IsStatic()) { 795 | (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty); 796 | } else { 797 | (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty); 798 | } 799 | if (UNLIKELY(self->GetException() == Thread::GetDeoptimizationException())) { 800 | // Unusual case where we were running generated code and an 801 | // exception was thrown to force the activations to be removed from the 802 | // stack. Continue execution in the interpreter. 803 | self->DeoptimizeWithDeoptimizationException(result); 804 | } 805 | if (kLogInvocationStartAndReturn) { 806 | LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod().c_str(), 807 | GetEntryPointFromQuickCompiledCode()); 808 | } 809 | } else { 810 | LOG(INFO) << "Not invoking '" << PrettyMethod() << "' code=null"; 811 | if (result != nullptr) { 812 | result->SetJ(0); 813 | } 814 | } 815 | } 816 | 817 | // Pop transition. 818 | self->PopManagedStackFragment(fragment); 819 | } 820 | 821 | const void* ArtMethod::RegisterNative(const void* native_method) { 822 | CHECK(IsNative()) << PrettyMethod(); 823 | CHECK(native_method != nullptr) << PrettyMethod(); 824 | void* new_native_method = nullptr; 825 | Runtime::Current()->GetRuntimeCallbacks()->RegisterNativeMethod(this, 826 | native_method, 827 | /*out*/&new_native_method); 828 | SetEntryPointFromJni(new_native_method); 829 | return new_native_method; 830 | } 831 | 832 | void ArtMethod::UnregisterNative() { 833 | CHECK(IsNative()) << PrettyMethod(); 834 | // restore stub to lookup native pointer via dlsym 835 | SetEntryPointFromJni(GetJniDlsymLookupStub()); 836 | } 837 | 838 | bool ArtMethod::IsOverridableByDefaultMethod() { 839 | return GetDeclaringClass()->IsInterface(); 840 | } 841 | 842 | bool ArtMethod::IsPolymorphicSignature() { 843 | // Methods with a polymorphic signature have constraints that they 844 | // are native and varargs and belong to either MethodHandle or VarHandle. 845 | if (!IsNative() || !IsVarargs()) { 846 | return false; 847 | } 848 | ObjPtr> class_roots = 849 | Runtime::Current()->GetClassLinker()->GetClassRoots(); 850 | ObjPtr cls = GetDeclaringClass(); 851 | return (cls == GetClassRoot(class_roots) || 852 | cls == GetClassRoot(class_roots)); 853 | } 854 | 855 | static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, 856 | uint16_t class_def_idx, 857 | uint32_t method_idx) { 858 | ClassAccessor accessor(dex_file, class_def_idx); 859 | uint32_t class_def_method_index = 0u; 860 | for (const ClassAccessor::Method& method : accessor.GetMethods()) { 861 | if (method.GetIndex() == method_idx) { 862 | return class_def_method_index; 863 | } 864 | class_def_method_index++; 865 | } 866 | LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation(); 867 | UNREACHABLE(); 868 | } 869 | 870 | // We use the method's DexFile and declaring class name to find the OatMethod for an obsolete 871 | // method. This is extremely slow but we need it if we want to be able to have obsolete native 872 | // methods since we need this to find the size of its stack frames. 873 | // 874 | // NB We could (potentially) do this differently and rely on the way the transformation is applied 875 | // in order to use the entrypoint to find this information. However, for debugging reasons (most 876 | // notably making sure that new invokes of obsolete methods fail) we choose to instead get the data 877 | // directly from the dex file. 878 | static const OatFile::OatMethod FindOatMethodFromDexFileFor(ArtMethod* method, bool* found) 879 | REQUIRES_SHARED(Locks::mutator_lock_) { 880 | DCHECK(method->IsObsolete() && method->IsNative()); 881 | const DexFile* dex_file = method->GetDexFile(); 882 | 883 | // recreate the class_def_index from the descriptor. 884 | std::string descriptor_storage; 885 | const dex::TypeId* declaring_class_type_id = 886 | dex_file->FindTypeId(method->GetDeclaringClass()->GetDescriptor(&descriptor_storage)); 887 | CHECK(declaring_class_type_id != nullptr); 888 | dex::TypeIndex declaring_class_type_index = dex_file->GetIndexForTypeId(*declaring_class_type_id); 889 | const dex::ClassDef* declaring_class_type_def = 890 | dex_file->FindClassDef(declaring_class_type_index); 891 | CHECK(declaring_class_type_def != nullptr); 892 | uint16_t declaring_class_def_index = dex_file->GetIndexForClassDef(*declaring_class_type_def); 893 | 894 | size_t oat_method_index = GetOatMethodIndexFromMethodIndex(*dex_file, 895 | declaring_class_def_index, 896 | method->GetDexMethodIndex()); 897 | 898 | OatFile::OatClass oat_class = OatFile::FindOatClass(*dex_file, 899 | declaring_class_def_index, 900 | found); 901 | if (!(*found)) { 902 | return OatFile::OatMethod::Invalid(); 903 | } 904 | return oat_class.GetOatMethod(oat_method_index); 905 | } 906 | 907 | static const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, 908 | PointerSize pointer_size, 909 | bool* found) 910 | REQUIRES_SHARED(Locks::mutator_lock_) { 911 | if (UNLIKELY(method->IsObsolete())) { 912 | // We shouldn't be calling this with obsolete methods except for native obsolete methods for 913 | // which we need to use the oat method to figure out how large the quick frame is. 914 | DCHECK(method->IsNative()) << "We should only be finding the OatMethod of obsolete methods in " 915 | << "order to allow stack walking. Other obsolete methods should " 916 | << "never need to access this information."; 917 | DCHECK_EQ(pointer_size, kRuntimePointerSize) << "Obsolete method in compiler!"; 918 | return FindOatMethodFromDexFileFor(method, found); 919 | } 920 | // Although we overwrite the trampoline of non-static methods, we may get here via the resolution 921 | // method for direct methods (or virtual methods made direct). 922 | ObjPtr declaring_class = method->GetDeclaringClass(); 923 | size_t oat_method_index; 924 | if (method->IsStatic() || method->IsDirect()) { 925 | // Simple case where the oat method index was stashed at load time. 926 | oat_method_index = method->GetMethodIndex(); 927 | } else { 928 | // Compute the oat_method_index by search for its position in the declared virtual methods. 929 | oat_method_index = declaring_class->NumDirectMethods(); 930 | bool found_virtual = false; 931 | for (ArtMethod& art_method : declaring_class->GetVirtualMethods(pointer_size)) { 932 | // Check method index instead of identity in case of duplicate method definitions. 933 | if (method->GetDexMethodIndex() == art_method.GetDexMethodIndex()) { 934 | found_virtual = true; 935 | break; 936 | } 937 | oat_method_index++; 938 | } 939 | CHECK(found_virtual) << "Didn't find oat method index for virtual method: " 940 | << method->PrettyMethod(); 941 | } 942 | DCHECK_EQ(oat_method_index, 943 | GetOatMethodIndexFromMethodIndex(declaring_class->GetDexFile(), 944 | method->GetDeclaringClass()->GetDexClassDefIndex(), 945 | method->GetDexMethodIndex())); 946 | OatFile::OatClass oat_class = OatFile::FindOatClass(declaring_class->GetDexFile(), 947 | declaring_class->GetDexClassDefIndex(), 948 | found); 949 | if (!(*found)) { 950 | return OatFile::OatMethod::Invalid(); 951 | } 952 | return oat_class.GetOatMethod(oat_method_index); 953 | } 954 | 955 | bool ArtMethod::EqualParameters(Handle> params) { 956 | const DexFile* dex_file = GetDexFile(); 957 | const auto& method_id = dex_file->GetMethodId(GetDexMethodIndex()); 958 | const auto& proto_id = dex_file->GetMethodPrototype(method_id); 959 | const dex::TypeList* proto_params = dex_file->GetProtoParameters(proto_id); 960 | auto count = proto_params != nullptr ? proto_params->Size() : 0u; 961 | auto param_len = params != nullptr ? params->GetLength() : 0u; 962 | if (param_len != count) { 963 | return false; 964 | } 965 | auto* cl = Runtime::Current()->GetClassLinker(); 966 | for (size_t i = 0; i < count; ++i) { 967 | dex::TypeIndex type_idx = proto_params->GetTypeItem(i).type_idx_; 968 | ObjPtr type = cl->ResolveType(type_idx, this); 969 | if (type == nullptr) { 970 | Thread::Current()->AssertPendingException(); 971 | return false; 972 | } 973 | if (type != params->GetWithoutChecks(i)) { 974 | return false; 975 | } 976 | } 977 | return true; 978 | } 979 | 980 | ArrayRef ArtMethod::GetQuickenedInfo() { 981 | const DexFile& dex_file = *GetDexFile(); 982 | const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); 983 | if (oat_dex_file == nullptr) { 984 | return ArrayRef(); 985 | } 986 | return oat_dex_file->GetQuickenedInfoOf(dex_file, GetDexMethodIndex()); 987 | } 988 | 989 | uint16_t ArtMethod::GetIndexFromQuickening(uint32_t dex_pc) { 990 | ArrayRef data = GetQuickenedInfo(); 991 | if (data.empty()) { 992 | return DexFile::kDexNoIndex16; 993 | } 994 | QuickenInfoTable table(data); 995 | uint32_t quicken_index = 0; 996 | for (const DexInstructionPcPair& pair : DexInstructions()) { 997 | if (pair.DexPc() == dex_pc) { 998 | return table.GetData(quicken_index); 999 | } 1000 | if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) { 1001 | ++quicken_index; 1002 | } 1003 | } 1004 | return DexFile::kDexNoIndex16; 1005 | } 1006 | 1007 | const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { 1008 | // Our callers should make sure they don't pass the instrumentation exit pc, 1009 | // as this method does not look at the side instrumentation stack. 1010 | DCHECK_NE(pc, reinterpret_cast(GetQuickInstrumentationExitPc())); 1011 | 1012 | if (IsRuntimeMethod()) { 1013 | return nullptr; 1014 | } 1015 | 1016 | Runtime* runtime = Runtime::Current(); 1017 | const void* existing_entry_point = GetEntryPointFromQuickCompiledCode(); 1018 | CHECK(existing_entry_point != nullptr) << PrettyMethod() << "@" << this; 1019 | ClassLinker* class_linker = runtime->GetClassLinker(); 1020 | 1021 | if (existing_entry_point == GetQuickProxyInvokeHandler()) { 1022 | DCHECK(IsProxyMethod() && !IsConstructor()); 1023 | // The proxy entry point does not have any method header. 1024 | return nullptr; 1025 | } 1026 | 1027 | // Check whether the current entry point contains this pc. 1028 | if (!class_linker->IsQuickGenericJniStub(existing_entry_point) && 1029 | !class_linker->IsQuickResolutionStub(existing_entry_point) && 1030 | !class_linker->IsQuickToInterpreterBridge(existing_entry_point) && 1031 | existing_entry_point != GetQuickInstrumentationEntryPoint()) { 1032 | OatQuickMethodHeader* method_header = 1033 | OatQuickMethodHeader::FromEntryPoint(existing_entry_point); 1034 | 1035 | if (method_header->Contains(pc)) { 1036 | return method_header; 1037 | } 1038 | } 1039 | 1040 | // Check whether the pc is in the JIT code cache. 1041 | jit::Jit* jit = runtime->GetJit(); 1042 | if (jit != nullptr) { 1043 | jit::JitCodeCache* code_cache = jit->GetCodeCache(); 1044 | OatQuickMethodHeader* method_header = code_cache->LookupMethodHeader(pc, this); 1045 | if (method_header != nullptr) { 1046 | DCHECK(method_header->Contains(pc)); 1047 | return method_header; 1048 | } else { 1049 | DCHECK(!code_cache->ContainsPc(reinterpret_cast(pc))) 1050 | << PrettyMethod() 1051 | << ", pc=" << std::hex << pc 1052 | << ", entry_point=" << std::hex << reinterpret_cast(existing_entry_point) 1053 | << ", copy=" << std::boolalpha << IsCopied() 1054 | << ", proxy=" << std::boolalpha << IsProxyMethod(); 1055 | } 1056 | } 1057 | 1058 | // The code has to be in an oat file. 1059 | bool found; 1060 | OatFile::OatMethod oat_method = 1061 | FindOatMethodFor(this, class_linker->GetImagePointerSize(), &found); 1062 | if (!found) { 1063 | if (IsNative()) { 1064 | // We are running the GenericJNI stub. The entrypoint may point 1065 | // to different entrypoints or to a JIT-compiled JNI stub. 1066 | DCHECK(class_linker->IsQuickGenericJniStub(existing_entry_point) || 1067 | class_linker->IsQuickResolutionStub(existing_entry_point) || 1068 | existing_entry_point == GetQuickInstrumentationEntryPoint() || 1069 | (jit != nullptr && jit->GetCodeCache()->ContainsPc(existing_entry_point))); 1070 | return nullptr; 1071 | } 1072 | // Only for unit tests. 1073 | // TODO(ngeoffray): Update these tests to pass the right pc? 1074 | return OatQuickMethodHeader::FromEntryPoint(existing_entry_point); 1075 | } 1076 | const void* oat_entry_point = oat_method.GetQuickCode(); 1077 | if (oat_entry_point == nullptr || class_linker->IsQuickGenericJniStub(oat_entry_point)) { 1078 | DCHECK(IsNative()) << PrettyMethod(); 1079 | return nullptr; 1080 | } 1081 | 1082 | OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromEntryPoint(oat_entry_point); 1083 | if (pc == 0) { 1084 | // This is a downcall, it can only happen for a native method. 1085 | DCHECK(IsNative()); 1086 | return method_header; 1087 | } 1088 | 1089 | DCHECK(method_header->Contains(pc)) 1090 | << PrettyMethod() 1091 | << " " << std::hex << pc << " " << oat_entry_point 1092 | << " " << (uintptr_t)(method_header->GetCode() + method_header->GetCodeSize()); 1093 | return method_header; 1094 | } 1095 | 1096 | const void* ArtMethod::GetOatMethodQuickCode(PointerSize pointer_size) { 1097 | bool found; 1098 | OatFile::OatMethod oat_method = FindOatMethodFor(this, pointer_size, &found); 1099 | if (found) { 1100 | return oat_method.GetQuickCode(); 1101 | } 1102 | return nullptr; 1103 | } 1104 | 1105 | bool ArtMethod::HasAnyCompiledCode() { 1106 | if (IsNative() || !IsInvokable() || IsProxyMethod()) { 1107 | return false; 1108 | } 1109 | 1110 | // Check whether the JIT has compiled it. 1111 | Runtime* runtime = Runtime::Current(); 1112 | jit::Jit* jit = runtime->GetJit(); 1113 | if (jit != nullptr && jit->GetCodeCache()->ContainsMethod(this)) { 1114 | return true; 1115 | } 1116 | 1117 | // Check whether we have AOT code. 1118 | return GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()) != nullptr; 1119 | } 1120 | 1121 | void ArtMethod::SetIntrinsic(uint32_t intrinsic) { 1122 | // Currently we only do intrinsics for static/final methods or methods of final 1123 | // classes. We don't set kHasSingleImplementation for those methods. 1124 | DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) << 1125 | "Potential conflict with kAccSingleImplementation"; 1126 | static const int kAccFlagsShift = CTZ(kAccIntrinsicBits); 1127 | DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift); 1128 | uint32_t intrinsic_bits = intrinsic << kAccFlagsShift; 1129 | uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits; 1130 | if (kIsDebugBuild) { 1131 | uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask); 1132 | bool is_constructor = IsConstructor(); 1133 | bool is_synchronized = IsSynchronized(); 1134 | bool skip_access_checks = SkipAccessChecks(); 1135 | bool is_fast_native = IsFastNative(); 1136 | bool is_critical_native = IsCriticalNative(); 1137 | bool is_copied = IsCopied(); 1138 | bool is_miranda = IsMiranda(); 1139 | bool is_default = IsDefault(); 1140 | bool is_default_conflict = IsDefaultConflicting(); 1141 | bool is_compilable = IsCompilable(); 1142 | bool must_count_locks = MustCountLocks(); 1143 | // Recompute flags instead of getting them from the current access flags because 1144 | // access flags may have been changed to deduplicate warning messages (b/129063331). 1145 | uint32_t hiddenapi_flags = hiddenapi::CreateRuntimeFlags(this); 1146 | SetAccessFlags(new_value); 1147 | DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask)); 1148 | DCHECK_EQ(is_constructor, IsConstructor()); 1149 | DCHECK_EQ(is_synchronized, IsSynchronized()); 1150 | DCHECK_EQ(skip_access_checks, SkipAccessChecks()); 1151 | DCHECK_EQ(is_fast_native, IsFastNative()); 1152 | DCHECK_EQ(is_critical_native, IsCriticalNative()); 1153 | DCHECK_EQ(is_copied, IsCopied()); 1154 | DCHECK_EQ(is_miranda, IsMiranda()); 1155 | DCHECK_EQ(is_default, IsDefault()); 1156 | DCHECK_EQ(is_default_conflict, IsDefaultConflicting()); 1157 | DCHECK_EQ(is_compilable, IsCompilable()); 1158 | DCHECK_EQ(must_count_locks, MustCountLocks()); 1159 | // Only DCHECK that we have preserved the hidden API access flags if the 1160 | // original method was not on the whitelist. This is because the core image 1161 | // does not have the access flags set (b/77733081). 1162 | if ((hiddenapi_flags & kAccHiddenapiBits) != kAccPublicApi) { 1163 | DCHECK_EQ(hiddenapi_flags, hiddenapi::GetRuntimeFlags(this)) << PrettyMethod(); 1164 | } 1165 | } else { 1166 | SetAccessFlags(new_value); 1167 | } 1168 | } 1169 | 1170 | void ArtMethod::SetNotIntrinsic() { 1171 | if (!IsIntrinsic()) { 1172 | return; 1173 | } 1174 | 1175 | // Read the existing hiddenapi flags. 1176 | uint32_t hiddenapi_runtime_flags = hiddenapi::GetRuntimeFlags(this); 1177 | 1178 | // Clear intrinsic-related access flags. 1179 | ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits); 1180 | 1181 | // Re-apply hidden API access flags now that the method is not an intrinsic. 1182 | SetAccessFlags(GetAccessFlags() | hiddenapi_runtime_flags); 1183 | DCHECK_EQ(hiddenapi_runtime_flags, hiddenapi::GetRuntimeFlags(this)); 1184 | } 1185 | 1186 | void ArtMethod::CopyFrom(ArtMethod* src, PointerSize image_pointer_size) { 1187 | memcpy(reinterpret_cast(this), reinterpret_cast(src), 1188 | Size(image_pointer_size)); 1189 | declaring_class_ = GcRoot(const_cast(src)->GetDeclaringClass()); 1190 | 1191 | // If the entry point of the method we are copying from is from JIT code, we just 1192 | // put the entry point of the new method to interpreter or GenericJNI. We could set 1193 | // the entry point to the JIT code, but this would require taking the JIT code cache 1194 | // lock to notify it, which we do not want at this level. 1195 | Runtime* runtime = Runtime::Current(); 1196 | if (runtime->UseJitCompilation()) { 1197 | if (runtime->GetJit()->GetCodeCache()->ContainsPc(GetEntryPointFromQuickCompiledCode())) { 1198 | SetEntryPointFromQuickCompiledCodePtrSize( 1199 | src->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge(), 1200 | image_pointer_size); 1201 | } 1202 | } 1203 | // Clear the profiling info for the same reasons as the JIT code. 1204 | if (!src->IsNative()) { 1205 | SetProfilingInfoPtrSize(nullptr, image_pointer_size); 1206 | } 1207 | // Clear hotness to let the JIT properly decide when to compile this method. 1208 | hotness_count_ = 0; 1209 | } 1210 | 1211 | bool ArtMethod::IsImagePointerSize(PointerSize pointer_size) { 1212 | // Hijack this function to get access to PtrSizedFieldsOffset. 1213 | // 1214 | // Ensure that PrtSizedFieldsOffset is correct. We rely here on usually having both 32-bit and 1215 | // 64-bit builds. 1216 | static_assert(std::is_standard_layout::value, "ArtMethod is not standard layout."); 1217 | static_assert( 1218 | (sizeof(void*) != 4) || 1219 | (offsetof(ArtMethod, ptr_sized_fields_) == PtrSizedFieldsOffset(PointerSize::k32)), 1220 | "Unexpected 32-bit class layout."); 1221 | static_assert( 1222 | (sizeof(void*) != 8) || 1223 | (offsetof(ArtMethod, ptr_sized_fields_) == PtrSizedFieldsOffset(PointerSize::k64)), 1224 | "Unexpected 64-bit class layout."); 1225 | 1226 | Runtime* runtime = Runtime::Current(); 1227 | if (runtime == nullptr) { 1228 | return true; 1229 | } 1230 | return runtime->GetClassLinker()->GetImagePointerSize() == pointer_size; 1231 | } 1232 | 1233 | std::string ArtMethod::PrettyMethod(ArtMethod* m, bool with_signature) { 1234 | if (m == nullptr) { 1235 | return "null"; 1236 | } 1237 | return m->PrettyMethod(with_signature); 1238 | } 1239 | 1240 | std::string ArtMethod::PrettyMethod(bool with_signature) { 1241 | if (UNLIKELY(IsRuntimeMethod())) { 1242 | std::string result = GetDeclaringClassDescriptor(); 1243 | result += '.'; 1244 | result += GetName(); 1245 | // Do not add "" even if `with_signature` is true. 1246 | return result; 1247 | } 1248 | ArtMethod* m = 1249 | GetInterfaceMethodIfProxy(Runtime::Current()->GetClassLinker()->GetImagePointerSize()); 1250 | std::string res(m->GetDexFile()->PrettyMethod(m->GetDexMethodIndex(), with_signature)); 1251 | if (with_signature && m->IsObsolete()) { 1252 | return " " + res; 1253 | } else { 1254 | return res; 1255 | } 1256 | } 1257 | 1258 | std::string ArtMethod::JniShortName() { 1259 | return GetJniShortName(GetDeclaringClassDescriptor(), GetName()); 1260 | } 1261 | 1262 | std::string ArtMethod::JniLongName() { 1263 | std::string long_name; 1264 | long_name += JniShortName(); 1265 | long_name += "__"; 1266 | 1267 | std::string signature(GetSignature().ToString()); 1268 | signature.erase(0, 1); 1269 | signature.erase(signature.begin() + signature.find(')'), signature.end()); 1270 | 1271 | long_name += MangleForJni(signature); 1272 | 1273 | return long_name; 1274 | } 1275 | 1276 | const char* ArtMethod::GetRuntimeMethodName() { 1277 | Runtime* const runtime = Runtime::Current(); 1278 | if (this == runtime->GetResolutionMethod()) { 1279 | return ""; 1280 | } else if (this == runtime->GetImtConflictMethod()) { 1281 | return ""; 1282 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) { 1283 | return ""; 1284 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly)) { 1285 | return ""; 1286 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs)) { 1287 | return ""; 1288 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything)) { 1289 | return ""; 1290 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit)) { 1291 | return ""; 1292 | } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck)) { 1293 | return ""; 1294 | } else { 1295 | return ""; 1296 | } 1297 | } 1298 | 1299 | // AssertSharedHeld doesn't work in GetAccessFlags, so use a NO_THREAD_SAFETY_ANALYSIS helper. 1300 | // TODO: Figure out why ASSERT_SHARED_CAPABILITY doesn't work. 1301 | template 1302 | ALWAYS_INLINE static inline void DoGetAccessFlagsHelper(ArtMethod* method) 1303 | NO_THREAD_SAFETY_ANALYSIS { 1304 | CHECK(method->IsRuntimeMethod() || 1305 | method->GetDeclaringClass()->IsIdxLoaded() || 1306 | method->GetDeclaringClass()->IsErroneous()); 1307 | } 1308 | 1309 | } // namespace art 1310 | -------------------------------------------------------------------------------- /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 | #include 21 | 22 | #include "common_dex_operations.h" 23 | #include "common_throws.h" 24 | #include "dex/dex_file_types.h" 25 | #include "interpreter_common.h" 26 | #include "interpreter_mterp_impl.h" 27 | #include "interpreter_switch_impl.h" 28 | #include "jit/jit.h" 29 | #include "jit/jit_code_cache.h" 30 | #include "jvalue-inl.h" 31 | #include "mirror/string-inl.h" 32 | #include "mterp/mterp.h" 33 | #include "nativehelper/scoped_local_ref.h" 34 | #include "scoped_thread_state_change-inl.h" 35 | #include "shadow_frame-inl.h" 36 | #include "stack.h" 37 | #include "thread-inl.h" 38 | #include "unstarted_runtime.h" 39 | 40 | namespace art { 41 | 42 | extern "C" bool ShouldUnpack(); 43 | 44 | namespace interpreter { 45 | //add 46 | extern "C" void dumpdexfilebyExecute(ArtMethod* artmethod); 47 | //addend 48 | ALWAYS_INLINE static ObjPtr ObjArg(uint32_t arg) 49 | REQUIRES_SHARED(Locks::mutator_lock_) { 50 | return reinterpret_cast(arg); 51 | } 52 | 53 | static void InterpreterJni(Thread* self, 54 | ArtMethod* method, 55 | std::string_view shorty, 56 | ObjPtr receiver, 57 | uint32_t* args, 58 | JValue* result) 59 | REQUIRES_SHARED(Locks::mutator_lock_) { 60 | // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler, 61 | // it should be removed and JNI compiled stubs used instead. 62 | ScopedObjectAccessUnchecked soa(self); 63 | if (method->IsStatic()) { 64 | if (shorty == "L") { 65 | using fntype = jobject(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 | } else if (shorty == "V") { 76 | using fntype = void(JNIEnv*, jclass); 77 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 78 | ScopedLocalRef klass(soa.Env(), 79 | soa.AddLocalReference(method->GetDeclaringClass())); 80 | ScopedThreadStateChange tsc(self, kNative); 81 | fn(soa.Env(), klass.get()); 82 | } else if (shorty == "Z") { 83 | using fntype = jboolean(JNIEnv*, jclass); 84 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 85 | ScopedLocalRef klass(soa.Env(), 86 | soa.AddLocalReference(method->GetDeclaringClass())); 87 | ScopedThreadStateChange tsc(self, kNative); 88 | result->SetZ(fn(soa.Env(), klass.get())); 89 | } else if (shorty == "BI") { 90 | using fntype = jbyte(JNIEnv*, jclass, jint); 91 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 92 | ScopedLocalRef klass(soa.Env(), 93 | soa.AddLocalReference(method->GetDeclaringClass())); 94 | ScopedThreadStateChange tsc(self, kNative); 95 | result->SetB(fn(soa.Env(), klass.get(), args[0])); 96 | } else if (shorty == "II") { 97 | using fntype = jint(JNIEnv*, jclass, jint); 98 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 99 | ScopedLocalRef klass(soa.Env(), 100 | soa.AddLocalReference(method->GetDeclaringClass())); 101 | ScopedThreadStateChange tsc(self, kNative); 102 | result->SetI(fn(soa.Env(), klass.get(), args[0])); 103 | } else if (shorty == "LL") { 104 | using fntype = jobject(JNIEnv*, jclass, jobject); 105 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 106 | ScopedLocalRef klass(soa.Env(), 107 | soa.AddLocalReference(method->GetDeclaringClass())); 108 | ScopedLocalRef arg0(soa.Env(), 109 | soa.AddLocalReference(ObjArg(args[0]))); 110 | jobject jresult; 111 | { 112 | ScopedThreadStateChange tsc(self, kNative); 113 | jresult = fn(soa.Env(), klass.get(), arg0.get()); 114 | } 115 | result->SetL(soa.Decode(jresult)); 116 | } else if (shorty == "IIZ") { 117 | using fntype = jint(JNIEnv*, jclass, jint, jboolean); 118 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 119 | ScopedLocalRef klass(soa.Env(), 120 | soa.AddLocalReference(method->GetDeclaringClass())); 121 | ScopedThreadStateChange tsc(self, kNative); 122 | result->SetI(fn(soa.Env(), klass.get(), args[0], args[1])); 123 | } else if (shorty == "ILI") { 124 | using fntype = jint(JNIEnv*, jclass, jobject, jint); 125 | fntype* const fn = reinterpret_cast(const_cast( 126 | method->GetEntryPointFromJni())); 127 | ScopedLocalRef klass(soa.Env(), 128 | soa.AddLocalReference(method->GetDeclaringClass())); 129 | ScopedLocalRef arg0(soa.Env(), 130 | soa.AddLocalReference(ObjArg(args[0]))); 131 | ScopedThreadStateChange tsc(self, kNative); 132 | result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1])); 133 | } else if (shorty == "SIZ") { 134 | using fntype = jshort(JNIEnv*, jclass, jint, jboolean); 135 | fntype* const fn = 136 | reinterpret_cast(const_cast(method->GetEntryPointFromJni())); 137 | ScopedLocalRef klass(soa.Env(), 138 | soa.AddLocalReference(method->GetDeclaringClass())); 139 | ScopedThreadStateChange tsc(self, kNative); 140 | result->SetS(fn(soa.Env(), klass.get(), args[0], args[1])); 141 | } else if (shorty == "VIZ") { 142 | using fntype = void(JNIEnv*, jclass, jint, jboolean); 143 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 144 | ScopedLocalRef klass(soa.Env(), 145 | soa.AddLocalReference(method->GetDeclaringClass())); 146 | ScopedThreadStateChange tsc(self, kNative); 147 | fn(soa.Env(), klass.get(), args[0], args[1]); 148 | } else if (shorty == "ZLL") { 149 | using fntype = jboolean(JNIEnv*, jclass, jobject, jobject); 150 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 151 | ScopedLocalRef klass(soa.Env(), 152 | soa.AddLocalReference(method->GetDeclaringClass())); 153 | ScopedLocalRef arg0(soa.Env(), 154 | soa.AddLocalReference(ObjArg(args[0]))); 155 | ScopedLocalRef arg1(soa.Env(), 156 | soa.AddLocalReference(ObjArg(args[1]))); 157 | ScopedThreadStateChange tsc(self, kNative); 158 | result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get())); 159 | } else if (shorty == "ZILL") { 160 | using fntype = jboolean(JNIEnv*, jclass, jint, jobject, jobject); 161 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 162 | ScopedLocalRef klass(soa.Env(), 163 | soa.AddLocalReference(method->GetDeclaringClass())); 164 | ScopedLocalRef arg1(soa.Env(), 165 | soa.AddLocalReference(ObjArg(args[1]))); 166 | ScopedLocalRef arg2(soa.Env(), 167 | soa.AddLocalReference(ObjArg(args[2]))); 168 | ScopedThreadStateChange tsc(self, kNative); 169 | result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get())); 170 | } else if (shorty == "VILII") { 171 | using fntype = void(JNIEnv*, jclass, jint, jobject, jint, jint); 172 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 173 | ScopedLocalRef klass(soa.Env(), 174 | soa.AddLocalReference(method->GetDeclaringClass())); 175 | ScopedLocalRef arg1(soa.Env(), 176 | soa.AddLocalReference(ObjArg(args[1]))); 177 | ScopedThreadStateChange tsc(self, kNative); 178 | fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]); 179 | } else if (shorty == "VLILII") { 180 | using fntype = void(JNIEnv*, jclass, jobject, jint, jobject, jint, jint); 181 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 182 | ScopedLocalRef klass(soa.Env(), 183 | soa.AddLocalReference(method->GetDeclaringClass())); 184 | ScopedLocalRef arg0(soa.Env(), 185 | soa.AddLocalReference(ObjArg(args[0]))); 186 | ScopedLocalRef arg2(soa.Env(), 187 | soa.AddLocalReference(ObjArg(args[2]))); 188 | ScopedThreadStateChange tsc(self, kNative); 189 | fn(soa.Env(), klass.get(), arg0.get(), args[1], arg2.get(), args[3], args[4]); 190 | } else { 191 | LOG(FATAL) << "Do something with static native method: " << method->PrettyMethod() 192 | << " shorty: " << shorty; 193 | } 194 | } else { 195 | if (shorty == "L") { 196 | using fntype = jobject(JNIEnv*, jobject); 197 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 198 | ScopedLocalRef rcvr(soa.Env(), 199 | soa.AddLocalReference(receiver)); 200 | jobject jresult; 201 | { 202 | ScopedThreadStateChange tsc(self, kNative); 203 | jresult = fn(soa.Env(), rcvr.get()); 204 | } 205 | result->SetL(soa.Decode(jresult)); 206 | } else if (shorty == "V") { 207 | using fntype = void(JNIEnv*, jobject); 208 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 209 | ScopedLocalRef rcvr(soa.Env(), 210 | soa.AddLocalReference(receiver)); 211 | ScopedThreadStateChange tsc(self, kNative); 212 | fn(soa.Env(), rcvr.get()); 213 | } else if (shorty == "LL") { 214 | using fntype = jobject(JNIEnv*, jobject, jobject); 215 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 216 | ScopedLocalRef rcvr(soa.Env(), 217 | soa.AddLocalReference(receiver)); 218 | ScopedLocalRef arg0(soa.Env(), 219 | soa.AddLocalReference(ObjArg(args[0]))); 220 | jobject jresult; 221 | { 222 | ScopedThreadStateChange tsc(self, kNative); 223 | jresult = fn(soa.Env(), rcvr.get(), arg0.get()); 224 | } 225 | result->SetL(soa.Decode(jresult)); 226 | ScopedThreadStateChange tsc(self, kNative); 227 | } else if (shorty == "III") { 228 | using fntype = jint(JNIEnv*, jobject, jint, jint); 229 | fntype* const fn = reinterpret_cast(method->GetEntryPointFromJni()); 230 | ScopedLocalRef rcvr(soa.Env(), 231 | soa.AddLocalReference(receiver)); 232 | ScopedThreadStateChange tsc(self, kNative); 233 | result->SetI(fn(soa.Env(), rcvr.get(), args[0], args[1])); 234 | } else { 235 | LOG(FATAL) << "Do something with native method: " << method->PrettyMethod() 236 | << " shorty: " << shorty; 237 | } 238 | } 239 | } 240 | 241 | enum InterpreterImplKind { 242 | kSwitchImplKind, // Switch-based interpreter implementation. 243 | kMterpImplKind // Assembly interpreter 244 | }; 245 | 246 | #if ART_USE_CXX_INTERPRETER 247 | static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImplKind; 248 | #else 249 | static constexpr InterpreterImplKind kInterpreterImplKind = kMterpImplKind; 250 | #endif 251 | 252 | 253 | 254 | static inline JValue Execute( 255 | Thread* self, 256 | const CodeItemDataAccessor& accessor, 257 | ShadowFrame& shadow_frame, 258 | JValue result_register, 259 | bool stay_in_interpreter = false, 260 | bool from_deoptimize = false) REQUIRES_SHARED(Locks::mutator_lock_) { 261 | 262 | DCHECK(!shadow_frame.GetMethod()->IsAbstract()); 263 | DCHECK(!shadow_frame.GetMethod()->IsNative()); 264 | //add 265 | if(result_register.GetI()==111111){ 266 | LOG(ERROR) << "fartext Execute start "<PrettyMethod().c_str(); 267 | } 268 | if(strstr(shadow_frame.GetMethod()->PrettyMethod().c_str(),"")) 269 | { 270 | if(ShouldUnpack()){ 271 | dumpdexfilebyExecute(shadow_frame.GetMethod()); 272 | } 273 | 274 | } 275 | //add end 276 | // Check that we are using the right interpreter. 277 | if (kIsDebugBuild && self->UseMterp() != CanUseMterp()) { 278 | // The flag might be currently being updated on all threads. Retry with lock. 279 | MutexLock tll_mu(self, *Locks::thread_list_lock_); 280 | DCHECK_EQ(self->UseMterp(), CanUseMterp()); 281 | } 282 | 283 | if (LIKELY(!from_deoptimize)) { // Entering the method, but not via deoptimization. 284 | if (kIsDebugBuild) { 285 | CHECK_EQ(shadow_frame.GetDexPC(), 0u); 286 | self->AssertNoPendingException(); 287 | } 288 | instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); 289 | ArtMethod *method = shadow_frame.GetMethod(); 290 | 291 | if (UNLIKELY(instrumentation->HasMethodEntryListeners())) { 292 | instrumentation->MethodEnterEvent(self, 293 | shadow_frame.GetThisObject(accessor.InsSize()), 294 | method, 295 | 0); 296 | if (UNLIKELY(shadow_frame.GetForcePopFrame())) { 297 | // The caller will retry this invoke. Just return immediately without any value. 298 | DCHECK(Runtime::Current()->AreNonStandardExitsEnabled()); 299 | DCHECK(PrevFrameWillRetry(self, shadow_frame)); 300 | return JValue(); 301 | } 302 | if (UNLIKELY(self->IsExceptionPending())) { 303 | instrumentation->MethodUnwindEvent(self, 304 | shadow_frame.GetThisObject(accessor.InsSize()), 305 | method, 306 | 0); 307 | return JValue(); 308 | } 309 | } 310 | 311 | if (!stay_in_interpreter && !self->IsForceInterpreter()) { 312 | jit::Jit* jit = Runtime::Current()->GetJit(); 313 | if (jit != nullptr) { 314 | jit->MethodEntered(self, shadow_frame.GetMethod()); 315 | if (jit->CanInvokeCompiledCode(method)) { 316 | JValue result; 317 | 318 | // Pop the shadow frame before calling into compiled code. 319 | self->PopShadowFrame(); 320 | // Calculate the offset of the first input reg. The input registers are in the high regs. 321 | // It's ok to access the code item here since JIT code will have been touched by the 322 | // interpreter and compiler already. 323 | uint16_t arg_offset = accessor.RegistersSize() - accessor.InsSize(); 324 | ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result); 325 | // Push the shadow frame back as the caller will expect it. 326 | self->PushShadowFrame(&shadow_frame); 327 | 328 | return result; 329 | } 330 | } 331 | } 332 | } 333 | 334 | ArtMethod* method = shadow_frame.GetMethod(); 335 | 336 | DCheckStaticState(self, method); 337 | 338 | // Lock counting is a special version of accessibility checks, and for simplicity and 339 | // reduction of template parameters, we gate it behind access-checks mode. 340 | DCHECK(!method->SkipAccessChecks() || !method->MustCountLocks()); 341 | 342 | bool transaction_active = Runtime::Current()->IsActiveTransaction(); 343 | if (LIKELY(method->SkipAccessChecks())) { 344 | // Enter the "without access check" interpreter. 345 | if (kInterpreterImplKind == kMterpImplKind) { 346 | if (transaction_active) { 347 | // No Mterp variant - just use the switch interpreter. 348 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 349 | false); 350 | } else if (UNLIKELY(!Runtime::Current()->IsStarted())) { 351 | 352 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 353 | false); 354 | } else { 355 | while (true) { 356 | // Mterp does not support all instrumentation/debugging. 357 | if (!self->UseMterp()) { 358 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 359 | false); 360 | } 361 | bool returned = ExecuteMterpImpl(self, 362 | accessor.Insns(), 363 | &shadow_frame, 364 | &result_register); 365 | if (returned) { 366 | return result_register; 367 | } else { 368 | // Mterp didn't like that instruction. Single-step it with the reference interpreter. 369 | result_register = ExecuteSwitchImpl(self, accessor, shadow_frame, 370 | result_register, true); 371 | if (shadow_frame.GetDexPC() == dex::kDexNoIndex) { 372 | // Single-stepped a return or an exception not handled locally. Return to caller. 373 | return result_register; 374 | } 375 | } 376 | } 377 | } 378 | } else { 379 | DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind); 380 | if (transaction_active) { 381 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 382 | false); 383 | } else { 384 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 385 | false); 386 | } 387 | } 388 | } else { 389 | // Enter the "with access check" interpreter. 390 | 391 | // The boot classpath should really not have to run access checks. 392 | DCHECK(method->GetDeclaringClass()->GetClassLoader() != nullptr 393 | || Runtime::Current()->IsVerificationSoftFail() 394 | || Runtime::Current()->IsAotCompiler()) 395 | << method->PrettyMethod(); 396 | 397 | if (kInterpreterImplKind == kMterpImplKind) { 398 | // No access check variants for Mterp. Just use the switch version. 399 | if (transaction_active) { 400 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 401 | false); 402 | } else { 403 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 404 | false); 405 | } 406 | } else { 407 | DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind); 408 | if (transaction_active) { 409 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 410 | false); 411 | } else { 412 | return ExecuteSwitchImpl(self, accessor, shadow_frame, result_register, 413 | false); 414 | } 415 | } 416 | } 417 | } 418 | 419 | void EnterInterpreterFromInvoke(Thread* self, 420 | ArtMethod* method, 421 | ObjPtr receiver, 422 | uint32_t* args, 423 | JValue* result, 424 | bool stay_in_interpreter) { 425 | DCHECK_EQ(self, Thread::Current()); 426 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 427 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 428 | ThrowStackOverflowError(self); 429 | return; 430 | } 431 | 432 | // This can happen if we are in forced interpreter mode and an obsolete method is called using 433 | // reflection. 434 | if (UNLIKELY(method->IsObsolete())) { 435 | ThrowInternalError("Attempting to invoke obsolete version of '%s'.", 436 | method->PrettyMethod().c_str()); 437 | return; 438 | } 439 | const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke"); 440 | CodeItemDataAccessor accessor(method->DexInstructionData()); 441 | uint16_t num_regs; 442 | uint16_t num_ins; 443 | if (accessor.HasCodeItem()) { 444 | num_regs = accessor.RegistersSize(); 445 | num_ins = accessor.InsSize(); 446 | } else if (!method->IsInvokable()) { 447 | self->EndAssertNoThreadSuspension(old_cause); 448 | method->ThrowInvocationTimeError(); 449 | return; 450 | } else { 451 | DCHECK(method->IsNative()); 452 | num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty()); 453 | if (!method->IsStatic()) { 454 | num_regs++; 455 | num_ins++; 456 | } 457 | } 458 | // Set up shadow frame with matching number of reference slots to vregs. 459 | ShadowFrame* last_shadow_frame = self->GetManagedStack()->GetTopShadowFrame(); 460 | ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = 461 | CREATE_SHADOW_FRAME(num_regs, last_shadow_frame, method, /* dex pc */ 0); 462 | ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get(); 463 | self->PushShadowFrame(shadow_frame); 464 | 465 | size_t cur_reg = num_regs - num_ins; 466 | if (!method->IsStatic()) { 467 | 468 | //add 469 | if(result!=nullptr&&result->GetI()==111111){ 470 | shadow_frame->SetVReg(cur_reg, args[0]); 471 | }else{ 472 | CHECK(receiver != nullptr); 473 | shadow_frame->SetVRegReference(cur_reg, receiver); 474 | } 475 | //add end 476 | //shadow_frame->SetVRegReference(cur_reg, receiver); 477 | ++cur_reg; 478 | } 479 | uint32_t shorty_len = 0; 480 | const char* shorty = method->GetShorty(&shorty_len); 481 | for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) { 482 | DCHECK_LT(shorty_pos + 1, shorty_len); 483 | switch (shorty[shorty_pos + 1]) { 484 | case 'L': { 485 | //add 486 | if(result!=nullptr&&result->GetI()==111111){ 487 | shadow_frame->SetVReg(cur_reg, args[0]); 488 | break; 489 | } 490 | //add end 491 | ObjPtr o = 492 | reinterpret_cast*>(&args[arg_pos])->AsMirrorPtr(); 493 | shadow_frame->SetVRegReference(cur_reg, o); 494 | break; 495 | } 496 | case 'J': case 'D': { 497 | uint64_t wide_value = (static_cast(args[arg_pos + 1]) << 32) | args[arg_pos]; 498 | shadow_frame->SetVRegLong(cur_reg, wide_value); 499 | cur_reg++; 500 | arg_pos++; 501 | break; 502 | } 503 | default: 504 | shadow_frame->SetVReg(cur_reg, args[arg_pos]); 505 | break; 506 | } 507 | } 508 | self->EndAssertNoThreadSuspension(old_cause); 509 | // Do this after populating the shadow frame in case EnsureInitialized causes a GC. 510 | if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitialized())) { 511 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 512 | StackHandleScope<1> hs(self); 513 | Handle h_class(hs.NewHandle(method->GetDeclaringClass())); 514 | if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) { 515 | CHECK(self->IsExceptionPending()); 516 | self->PopShadowFrame(); 517 | return; 518 | } 519 | } 520 | if (LIKELY(!method->IsNative())) { 521 | if(result!=nullptr&&result->GetI()==111111){ 522 | JValue r = Execute(self, accessor, *shadow_frame, *result, stay_in_interpreter); 523 | if (result != nullptr) { 524 | *result = r; 525 | } 526 | LOG(ERROR) << "fartext Execute over"<PrettyMethod().c_str(); 527 | return; 528 | }else{ 529 | JValue r = Execute(self, accessor, *shadow_frame, JValue(), stay_in_interpreter); 530 | if (result != nullptr) { 531 | *result = r; 532 | } 533 | } 534 | } else { 535 | // We don't expect to be asked to interpret native code (which is entered via a JNI compiler 536 | // generated stub) except during testing and image writing. 537 | // Update args to be the args in the shadow frame since the input ones could hold stale 538 | // references pointers due to moving GC. 539 | args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1); 540 | if (!Runtime::Current()->IsStarted()) { 541 | UnstartedRuntime::Jni(self, method, receiver.Ptr(), args, result); 542 | } else { 543 | InterpreterJni(self, method, shorty, receiver, args, result); 544 | } 545 | } 546 | self->PopShadowFrame(); 547 | } 548 | 549 | static int16_t GetReceiverRegisterForStringInit(const Instruction* instr) { 550 | DCHECK(instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE || 551 | instr->Opcode() == Instruction::INVOKE_DIRECT); 552 | return (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ? 553 | instr->VRegC_3rc() : instr->VRegC_35c(); 554 | } 555 | 556 | void EnterInterpreterFromDeoptimize(Thread* self, 557 | ShadowFrame* shadow_frame, 558 | JValue* ret_val, 559 | bool from_code, 560 | DeoptimizationMethodType deopt_method_type) 561 | REQUIRES_SHARED(Locks::mutator_lock_) { 562 | JValue value; 563 | // Set value to last known result in case the shadow frame chain is empty. 564 | value.SetJ(ret_val->GetJ()); 565 | // How many frames we have executed. 566 | size_t frame_cnt = 0; 567 | while (shadow_frame != nullptr) { 568 | // We do not want to recover lock state for lock counting when deoptimizing. Currently, 569 | // the compiler should not have compiled a method that failed structured-locking checks. 570 | DCHECK(!shadow_frame->GetMethod()->MustCountLocks()); 571 | 572 | self->SetTopOfShadowStack(shadow_frame); 573 | CodeItemDataAccessor accessor(shadow_frame->GetMethod()->DexInstructionData()); 574 | const uint32_t dex_pc = shadow_frame->GetDexPC(); 575 | uint32_t new_dex_pc = dex_pc; 576 | if (UNLIKELY(self->IsExceptionPending())) { 577 | // If we deoptimize from the QuickExceptionHandler, we already reported the exception to 578 | // the instrumentation. To prevent from reporting it a second time, we simply pass a 579 | // null Instrumentation*. 580 | const instrumentation::Instrumentation* const instrumentation = 581 | frame_cnt == 0 ? nullptr : Runtime::Current()->GetInstrumentation(); 582 | new_dex_pc = MoveToExceptionHandler( 583 | self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex; 584 | } else if (!from_code) { 585 | // Deoptimization is not called from code directly. 586 | const Instruction* instr = &accessor.InstructionAt(dex_pc); 587 | if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc || 588 | shadow_frame->GetForceRetryInstruction()) { 589 | DCHECK(frame_cnt == 0 || (frame_cnt == 1 && shadow_frame->GetForceRetryInstruction())) 590 | << "frame_cnt: " << frame_cnt 591 | << " force-retry: " << shadow_frame->GetForceRetryInstruction(); 592 | // Need to re-execute the dex instruction. 593 | // (1) An invocation might be split into class initialization and invoke. 594 | // In this case, the invoke should not be skipped. 595 | // (2) A suspend check should also execute the dex instruction at the 596 | // corresponding dex pc. 597 | // If the ForceRetryInstruction bit is set this must be the second frame (the first being 598 | // the one that is being popped). 599 | DCHECK_EQ(new_dex_pc, dex_pc); 600 | shadow_frame->SetForceRetryInstruction(false); 601 | } else if (instr->Opcode() == Instruction::MONITOR_ENTER || 602 | instr->Opcode() == Instruction::MONITOR_EXIT) { 603 | DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); 604 | DCHECK_EQ(frame_cnt, 0u); 605 | // Non-idempotent dex instruction should not be re-executed. 606 | // On the other hand, if a MONITOR_ENTER is at the dex_pc of a suspend 607 | // check, that MONITOR_ENTER should be executed. That case is handled 608 | // above. 609 | new_dex_pc = dex_pc + instr->SizeInCodeUnits(); 610 | } else if (instr->IsInvoke()) { 611 | DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); 612 | if (IsStringInit(instr, shadow_frame->GetMethod())) { 613 | uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr); 614 | // Move the StringFactory.newStringFromChars() result into the register representing 615 | // "this object" when invoking the string constructor in the original dex instruction. 616 | // Also move the result into all aliases. 617 | DCHECK(value.GetL()->IsString()); 618 | SetStringInitValueToAllAliases(shadow_frame, this_obj_vreg, value); 619 | // Calling string constructor in the original dex code doesn't generate a result value. 620 | value.SetJ(0); 621 | } 622 | new_dex_pc = dex_pc + instr->SizeInCodeUnits(); 623 | } else if (instr->Opcode() == Instruction::NEW_INSTANCE) { 624 | // A NEW_INSTANCE is simply re-executed, including 625 | // "new-instance String" which is compiled into a call into 626 | // StringFactory.newEmptyString(). 627 | DCHECK_EQ(new_dex_pc, dex_pc); 628 | } else { 629 | DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); 630 | DCHECK_EQ(frame_cnt, 0u); 631 | // By default, we re-execute the dex instruction since if they are not 632 | // an invoke, so that we don't have to decode the dex instruction to move 633 | // result into the right vreg. All slow paths have been audited to be 634 | // idempotent except monitor-enter/exit and invocation stubs. 635 | // TODO: move result and advance dex pc. That also requires that we 636 | // can tell the return type of a runtime method, possibly by decoding 637 | // the dex instruction at the caller. 638 | DCHECK_EQ(new_dex_pc, dex_pc); 639 | } 640 | } else { 641 | // Nothing to do, the dex_pc is the one at which the code requested 642 | // the deoptimization. 643 | DCHECK_EQ(frame_cnt, 0u); 644 | DCHECK_EQ(new_dex_pc, dex_pc); 645 | } 646 | if (new_dex_pc != dex::kDexNoIndex) { 647 | shadow_frame->SetDexPC(new_dex_pc); 648 | value = Execute(self, 649 | accessor, 650 | *shadow_frame, 651 | value, 652 | /* stay_in_interpreter= */ true, 653 | /* from_deoptimize= */ true); 654 | } 655 | ShadowFrame* old_frame = shadow_frame; 656 | shadow_frame = shadow_frame->GetLink(); 657 | ShadowFrame::DeleteDeoptimizedFrame(old_frame); 658 | // Following deoptimizations of shadow frames must be at invocation point 659 | // and should advance dex pc past the invoke instruction. 660 | from_code = false; 661 | deopt_method_type = DeoptimizationMethodType::kDefault; 662 | frame_cnt++; 663 | } 664 | ret_val->SetJ(value.GetJ()); 665 | } 666 | 667 | JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor, 668 | ShadowFrame* shadow_frame) { 669 | DCHECK_EQ(self, Thread::Current()); 670 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 671 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 672 | ThrowStackOverflowError(self); 673 | return JValue(); 674 | } 675 | 676 | jit::Jit* jit = Runtime::Current()->GetJit(); 677 | if (jit != nullptr) { 678 | jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod()); 679 | } 680 | return Execute(self, accessor, *shadow_frame, JValue()); 681 | } 682 | 683 | void ArtInterpreterToInterpreterBridge(Thread* self, 684 | const CodeItemDataAccessor& accessor, 685 | ShadowFrame* shadow_frame, 686 | JValue* result) { 687 | bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 688 | if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 689 | ThrowStackOverflowError(self); 690 | return; 691 | } 692 | 693 | self->PushShadowFrame(shadow_frame); 694 | ArtMethod* method = shadow_frame->GetMethod(); 695 | // Ensure static methods are initialized. 696 | const bool is_static = method->IsStatic(); 697 | if (is_static) { 698 | ObjPtr declaring_class = method->GetDeclaringClass(); 699 | if (UNLIKELY(!declaring_class->IsInitialized())) { 700 | StackHandleScope<1> hs(self); 701 | HandleWrapperObjPtr h_declaring_class(hs.NewHandleWrapper(&declaring_class)); 702 | if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized( 703 | self, h_declaring_class, true, true))) { 704 | DCHECK(self->IsExceptionPending()); 705 | self->PopShadowFrame(); 706 | return; 707 | } 708 | CHECK(h_declaring_class->IsInitializing()); 709 | } 710 | } 711 | 712 | if (LIKELY(!shadow_frame->GetMethod()->IsNative())) { 713 | result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ()); 714 | } else { 715 | // We don't expect to be asked to interpret native code (which is entered via a JNI compiler 716 | // generated stub) except during testing and image writing. 717 | CHECK(!Runtime::Current()->IsStarted()); 718 | ObjPtr receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0); 719 | uint32_t* args = shadow_frame->GetVRegArgs(is_static ? 0 : 1); 720 | UnstartedRuntime::Jni(self, shadow_frame->GetMethod(), receiver.Ptr(), args, result); 721 | } 722 | 723 | self->PopShadowFrame(); 724 | } 725 | 726 | void CheckInterpreterAsmConstants() { 727 | CheckMterpAsmConstants(); 728 | } 729 | 730 | void InitInterpreterTls(Thread* self) { 731 | InitMterpTls(self); 732 | } 733 | 734 | bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame) { 735 | ShadowFrame* prev_frame = frame.GetLink(); 736 | if (prev_frame == nullptr) { 737 | NthCallerVisitor vis(self, 1, false); 738 | vis.WalkStack(); 739 | prev_frame = vis.GetCurrentShadowFrame(); 740 | if (prev_frame == nullptr) { 741 | prev_frame = self->FindDebuggerShadowFrame(vis.GetFrameId()); 742 | } 743 | } 744 | return prev_frame != nullptr && prev_frame->GetForceRetryInstruction(); 745 | } 746 | 747 | } // namespace interpreter 748 | } // namespace art 749 | -------------------------------------------------------------------------------- /art/runtime/native/dalvik_system_DexFile.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 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 "dalvik_system_DexFile.h" 18 | 19 | #include 20 | 21 | #include "android-base/stringprintf.h" 22 | 23 | #include "base/casts.h" 24 | #include "base/file_utils.h" 25 | #include "base/logging.h" 26 | #include "base/os.h" 27 | #include "base/stl_util.h" 28 | #include "base/utils.h" 29 | #include "base/zip_archive.h" 30 | #include "class_linker.h" 31 | #include "class_loader_context.h" 32 | #include "common_throws.h" 33 | #include "compiler_filter.h" 34 | #include "dex/art_dex_file_loader.h" 35 | #include "dex/descriptors_names.h" 36 | #include "dex/dex_file-inl.h" 37 | #include "dex/dex_file_loader.h" 38 | #include "handle_scope-inl.h" 39 | #include "jit/debugger_interface.h" 40 | #include "jni/jni_internal.h" 41 | #include "mirror/class_loader.h" 42 | #include "mirror/object-inl.h" 43 | #include "mirror/string.h" 44 | #include "native_util.h" 45 | #include "nativehelper/jni_macros.h" 46 | #include "nativehelper/scoped_local_ref.h" 47 | #include "nativehelper/scoped_utf_chars.h" 48 | #include "oat_file.h" 49 | #include "oat_file_assistant.h" 50 | #include "oat_file_manager.h" 51 | #include "runtime.h" 52 | #include "scoped_thread_state_change-inl.h" 53 | #include "well_known_classes.h" 54 | //add 55 | #include "scoped_fast_native_object_access.h" 56 | //add end 57 | namespace art { 58 | //add 59 | extern "C" void fartextInvoke(ArtMethod* artmethod); 60 | extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod); 61 | //add end 62 | using android::base::StringPrintf; 63 | 64 | static bool ConvertJavaArrayToDexFiles( 65 | JNIEnv* env, 66 | jobject arrayObject, 67 | /*out*/ std::vector& dex_files, 68 | /*out*/ const OatFile*& oat_file) { 69 | jarray array = reinterpret_cast(arrayObject); 70 | 71 | jsize array_size = env->GetArrayLength(array); 72 | if (env->ExceptionCheck() == JNI_TRUE) { 73 | return false; 74 | } 75 | 76 | // TODO: Optimize. On 32bit we can use an int array. 77 | jboolean is_long_data_copied; 78 | jlong* long_data = env->GetLongArrayElements(reinterpret_cast(array), 79 | &is_long_data_copied); 80 | if (env->ExceptionCheck() == JNI_TRUE) { 81 | return false; 82 | } 83 | 84 | oat_file = reinterpret_cast64(long_data[kOatFileIndex]); 85 | dex_files.reserve(array_size - 1); 86 | for (jsize i = kDexFileIndexStart; i < array_size; ++i) { 87 | dex_files.push_back(reinterpret_cast64(long_data[i])); 88 | } 89 | 90 | env->ReleaseLongArrayElements(reinterpret_cast(array), long_data, JNI_ABORT); 91 | return env->ExceptionCheck() != JNI_TRUE; 92 | } 93 | 94 | static jlongArray ConvertDexFilesToJavaArray(JNIEnv* env, 95 | const OatFile* oat_file, 96 | std::vector>& vec) { 97 | // Add one for the oat file. 98 | jlongArray long_array = env->NewLongArray(static_cast(kDexFileIndexStart + vec.size())); 99 | if (env->ExceptionCheck() == JNI_TRUE) { 100 | return nullptr; 101 | } 102 | 103 | jboolean is_long_data_copied; 104 | jlong* long_data = env->GetLongArrayElements(long_array, &is_long_data_copied); 105 | if (env->ExceptionCheck() == JNI_TRUE) { 106 | return nullptr; 107 | } 108 | 109 | long_data[kOatFileIndex] = reinterpret_cast64(oat_file); 110 | for (size_t i = 0; i < vec.size(); ++i) { 111 | long_data[kDexFileIndexStart + i] = reinterpret_cast64(vec[i].get()); 112 | } 113 | 114 | env->ReleaseLongArrayElements(long_array, long_data, 0); 115 | if (env->ExceptionCheck() == JNI_TRUE) { 116 | return nullptr; 117 | } 118 | 119 | // Now release all the unique_ptrs. 120 | for (auto& dex_file : vec) { 121 | dex_file.release(); // NOLINT 122 | } 123 | 124 | return long_array; 125 | } 126 | 127 | // A smart pointer that provides read-only access to a Java string's UTF chars. 128 | // Unlike libcore's NullableScopedUtfChars, this will *not* throw NullPointerException if 129 | // passed a null jstring. The correct idiom is: 130 | // 131 | // NullableScopedUtfChars name(env, javaName); 132 | // if (env->ExceptionCheck()) { 133 | // return null; 134 | // } 135 | // // ... use name.c_str() 136 | // 137 | // TODO: rewrite to get rid of this, or change ScopedUtfChars to offer this option. 138 | class NullableScopedUtfChars { 139 | public: 140 | NullableScopedUtfChars(JNIEnv* env, jstring s) : mEnv(env), mString(s) { 141 | mUtfChars = (s != nullptr) ? env->GetStringUTFChars(s, nullptr) : nullptr; 142 | } 143 | 144 | ~NullableScopedUtfChars() { 145 | if (mUtfChars) { 146 | mEnv->ReleaseStringUTFChars(mString, mUtfChars); 147 | } 148 | } 149 | 150 | const char* c_str() const { 151 | return mUtfChars; 152 | } 153 | 154 | size_t size() const { 155 | return strlen(mUtfChars); 156 | } 157 | 158 | // Element access. 159 | const char& operator[](size_t n) const { 160 | return mUtfChars[n]; 161 | } 162 | 163 | private: 164 | JNIEnv* mEnv; 165 | jstring mString; 166 | const char* mUtfChars; 167 | 168 | // Disallow copy and assignment. 169 | NullableScopedUtfChars(const NullableScopedUtfChars&); 170 | void operator=(const NullableScopedUtfChars&); 171 | }; 172 | 173 | static jobject CreateCookieFromOatFileManagerResult( 174 | JNIEnv* env, 175 | std::vector>& dex_files, 176 | const OatFile* oat_file, 177 | const std::vector& error_msgs) { 178 | ClassLinker* linker = Runtime::Current()->GetClassLinker(); 179 | if (dex_files.empty()) { 180 | ScopedObjectAccess soa(env); 181 | CHECK(!error_msgs.empty()); 182 | // The most important message is at the end. So set up nesting by going forward, which will 183 | // wrap the existing exception as a cause for the following one. 184 | auto it = error_msgs.begin(); 185 | auto itEnd = error_msgs.end(); 186 | for ( ; it != itEnd; ++it) { 187 | ThrowWrappedIOException("%s", it->c_str()); 188 | } 189 | return nullptr; 190 | } 191 | 192 | jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); 193 | if (array == nullptr) { 194 | ScopedObjectAccess soa(env); 195 | for (auto& dex_file : dex_files) { 196 | if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) { 197 | dex_file.release(); // NOLINT 198 | } 199 | } 200 | } 201 | return array; 202 | } 203 | 204 | static MemMap AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) { 205 | if (end <= start) { 206 | ScopedObjectAccess soa(env); 207 | ThrowWrappedIOException("Bad range"); 208 | return MemMap::Invalid(); 209 | } 210 | 211 | std::string error_message; 212 | size_t length = static_cast(end - start); 213 | MemMap dex_mem_map = MemMap::MapAnonymous("DEX data", 214 | length, 215 | PROT_READ | PROT_WRITE, 216 | /*low_4gb=*/ false, 217 | &error_message); 218 | if (!dex_mem_map.IsValid()) { 219 | ScopedObjectAccess soa(env); 220 | ThrowWrappedIOException("%s", error_message.c_str()); 221 | return MemMap::Invalid(); 222 | } 223 | return dex_mem_map; 224 | } 225 | 226 | struct ScopedIntArrayAccessor { 227 | public: 228 | ScopedIntArrayAccessor(JNIEnv* env, jintArray arr) : env_(env), array_(arr) { 229 | elements_ = env_->GetIntArrayElements(array_, /* isCopy= */ nullptr); 230 | CHECK(elements_ != nullptr); 231 | } 232 | 233 | ~ScopedIntArrayAccessor() { 234 | env_->ReleaseIntArrayElements(array_, elements_, JNI_ABORT); 235 | } 236 | 237 | jint Get(jsize index) const { return elements_[index]; } 238 | 239 | private: 240 | JNIEnv* env_; 241 | jintArray array_; 242 | jint* elements_; 243 | }; 244 | 245 | static jobject DexFile_openInMemoryDexFilesNative(JNIEnv* env, 246 | jclass, 247 | jobjectArray buffers, 248 | jobjectArray arrays, 249 | jintArray jstarts, 250 | jintArray jends, 251 | jobject class_loader, 252 | jobjectArray dex_elements) { 253 | jsize buffers_length = env->GetArrayLength(buffers); 254 | CHECK_EQ(buffers_length, env->GetArrayLength(arrays)); 255 | CHECK_EQ(buffers_length, env->GetArrayLength(jstarts)); 256 | CHECK_EQ(buffers_length, env->GetArrayLength(jends)); 257 | 258 | ScopedIntArrayAccessor starts(env, jstarts); 259 | ScopedIntArrayAccessor ends(env, jends); 260 | 261 | // Allocate memory for dex files and copy data from ByteBuffers. 262 | std::vector dex_mem_maps; 263 | dex_mem_maps.reserve(buffers_length); 264 | for (jsize i = 0; i < buffers_length; ++i) { 265 | jobject buffer = env->GetObjectArrayElement(buffers, i); 266 | jbyteArray array = reinterpret_cast(env->GetObjectArrayElement(arrays, i)); 267 | jint start = starts.Get(i); 268 | jint end = ends.Get(i); 269 | 270 | MemMap dex_data = AllocateDexMemoryMap(env, start, end); 271 | if (!dex_data.IsValid()) { 272 | DCHECK(Thread::Current()->IsExceptionPending()); 273 | return nullptr; 274 | } 275 | 276 | if (array == nullptr) { 277 | // Direct ByteBuffer 278 | uint8_t* base_address = reinterpret_cast(env->GetDirectBufferAddress(buffer)); 279 | if (base_address == nullptr) { 280 | ScopedObjectAccess soa(env); 281 | ThrowWrappedIOException("dexFileBuffer not direct"); 282 | return nullptr; 283 | } 284 | size_t length = static_cast(end - start); 285 | memcpy(dex_data.Begin(), base_address + start, length); 286 | } else { 287 | // ByteBuffer backed by a byte array 288 | jbyte* destination = reinterpret_cast(dex_data.Begin()); 289 | env->GetByteArrayRegion(array, start, end - start, destination); 290 | } 291 | 292 | dex_mem_maps.push_back(std::move(dex_data)); 293 | } 294 | 295 | // Hand MemMaps over to OatFileManager to open the dex files and potentially 296 | // create a backing OatFile instance from an anonymous vdex. 297 | std::vector error_msgs; 298 | const OatFile* oat_file = nullptr; 299 | std::vector> dex_files = 300 | Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(std::move(dex_mem_maps), 301 | class_loader, 302 | dex_elements, 303 | /*out*/ &oat_file, 304 | /*out*/ &error_msgs); 305 | return CreateCookieFromOatFileManagerResult(env, dex_files, oat_file, error_msgs); 306 | } 307 | 308 | // TODO(calin): clean up the unused parameters (here and in libcore). 309 | static jobject DexFile_openDexFileNative(JNIEnv* env, 310 | jclass, 311 | jstring javaSourceName, 312 | jstring javaOutputName ATTRIBUTE_UNUSED, 313 | jint flags ATTRIBUTE_UNUSED, 314 | jobject class_loader, 315 | jobjectArray dex_elements) { 316 | ScopedUtfChars sourceName(env, javaSourceName); 317 | if (sourceName.c_str() == nullptr) { 318 | return nullptr; 319 | } 320 | 321 | std::vector error_msgs; 322 | const OatFile* oat_file = nullptr; 323 | std::vector> dex_files = 324 | Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), 325 | class_loader, 326 | dex_elements, 327 | /*out*/ &oat_file, 328 | /*out*/ &error_msgs); 329 | return CreateCookieFromOatFileManagerResult(env, dex_files, oat_file, error_msgs); 330 | } 331 | 332 | static jstring DexFile_getClassLoaderContext(JNIEnv* env, 333 | jclass, 334 | jobject class_loader, 335 | jobjectArray dex_elements) { 336 | CHECK(class_loader != nullptr); 337 | constexpr const char* kBaseDir = ""; 338 | std::unique_ptr context = 339 | ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements); 340 | if (context == nullptr || !context->OpenDexFiles(kRuntimeISA, kBaseDir)) { 341 | LOG(WARNING) << "Could not establish class loader context"; 342 | return nullptr; 343 | } 344 | std::string str_context = context->EncodeContextForOatFile(kBaseDir); 345 | return env->NewStringUTF(str_context.c_str()); 346 | } 347 | 348 | static void DexFile_verifyInBackgroundNative(JNIEnv* env, 349 | jclass, 350 | jobject cookie, 351 | jobject class_loader, 352 | jstring class_loader_context) { 353 | CHECK(cookie != nullptr); 354 | CHECK(class_loader != nullptr); 355 | 356 | // Extract list of dex files from the cookie. 357 | std::vector dex_files; 358 | const OatFile* oat_file; 359 | if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) { 360 | Thread::Current()->AssertPendingException(); 361 | return; 362 | } 363 | CHECK(oat_file == nullptr) << "Called verifyInBackground on a dex file backed by oat"; 364 | 365 | ScopedUtfChars class_loader_context_utf(env, class_loader_context); 366 | if (env->ExceptionCheck()) { 367 | LOG(ERROR) << "Failed to unwrap class loader context string"; 368 | return; 369 | } 370 | 371 | // Hand over to OatFileManager to spawn a verification thread. 372 | Runtime::Current()->GetOatFileManager().RunBackgroundVerification( 373 | dex_files, 374 | class_loader, 375 | class_loader_context_utf.c_str()); 376 | } 377 | 378 | static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { 379 | std::vector dex_files; 380 | const OatFile* oat_file; 381 | if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) { 382 | Thread::Current()->AssertPendingException(); 383 | return JNI_FALSE; 384 | } 385 | Runtime* const runtime = Runtime::Current(); 386 | bool all_deleted = true; 387 | // We need to clear the caches since they may contain pointers to the dex instructions. 388 | // Different dex file can be loaded at the same memory location later by chance. 389 | Thread::ClearAllInterpreterCaches(); 390 | { 391 | ScopedObjectAccess soa(env); 392 | ObjPtr dex_files_object = soa.Decode(cookie); 393 | ObjPtr long_dex_files = dex_files_object->AsLongArray(); 394 | // Delete dex files associated with this dalvik.system.DexFile since there should not be running 395 | // code using it. dex_files is a vector due to multidex. 396 | ClassLinker* const class_linker = runtime->GetClassLinker(); 397 | int32_t i = kDexFileIndexStart; // Oat file is at index 0. 398 | for (const DexFile* dex_file : dex_files) { 399 | if (dex_file != nullptr) { 400 | RemoveNativeDebugInfoForDex(soa.Self(), dex_file); 401 | // Only delete the dex file if the dex cache is not found to prevent runtime crashes 402 | // if there are calls to DexFile.close while the ART DexFile is still in use. 403 | if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) { 404 | // Clear the element in the array so that we can call close again. 405 | long_dex_files->Set(i, 0); 406 | delete dex_file; 407 | } else { 408 | all_deleted = false; 409 | } 410 | } 411 | ++i; 412 | } 413 | } 414 | 415 | // oat_file can be null if we are running without dex2oat. 416 | if (all_deleted && oat_file != nullptr) { 417 | // If all of the dex files are no longer in use we can unmap the corresponding oat file. 418 | VLOG(class_linker) << "Unregistering " << oat_file; 419 | runtime->GetOatFileManager().UnRegisterAndDeleteOatFile(oat_file); 420 | } 421 | return all_deleted ? JNI_TRUE : JNI_FALSE; 422 | } 423 | 424 | static jclass DexFile_defineClassNative(JNIEnv* env, 425 | jclass, 426 | jstring javaName, 427 | jobject javaLoader, 428 | jobject cookie, 429 | jobject dexFile) { 430 | std::vector dex_files; 431 | const OatFile* oat_file; 432 | if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) { 433 | VLOG(class_linker) << "Failed to find dex_file"; 434 | DCHECK(env->ExceptionCheck()); 435 | return nullptr; 436 | } 437 | 438 | ScopedUtfChars class_name(env, javaName); 439 | if (class_name.c_str() == nullptr) { 440 | VLOG(class_linker) << "Failed to find class_name"; 441 | return nullptr; 442 | } 443 | const std::string descriptor(DotToDescriptor(class_name.c_str())); 444 | const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str())); 445 | for (auto& dex_file : dex_files) { 446 | const dex::ClassDef* dex_class_def = 447 | OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash); 448 | if (dex_class_def != nullptr) { 449 | ScopedObjectAccess soa(env); 450 | ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 451 | StackHandleScope<1> hs(soa.Self()); 452 | Handle class_loader( 453 | hs.NewHandle(soa.Decode(javaLoader))); 454 | ObjPtr dex_cache = 455 | class_linker->RegisterDexFile(*dex_file, class_loader.Get()); 456 | if (dex_cache == nullptr) { 457 | // OOME or InternalError (dexFile already registered with a different class loader). 458 | soa.Self()->AssertPendingException(); 459 | return nullptr; 460 | } 461 | ObjPtr result = class_linker->DefineClass(soa.Self(), 462 | descriptor.c_str(), 463 | hash, 464 | class_loader, 465 | *dex_file, 466 | *dex_class_def); 467 | // Add the used dex file. This only required for the DexFile.loadClass API since normal 468 | // class loaders already keep their dex files live. 469 | class_linker->InsertDexFileInToClassLoader(soa.Decode(dexFile), 470 | class_loader.Get()); 471 | if (result != nullptr) { 472 | VLOG(class_linker) << "DexFile_defineClassNative returning " << result 473 | << " for " << class_name.c_str(); 474 | return soa.AddLocalReference(result); 475 | } 476 | } 477 | } 478 | VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str(); 479 | return nullptr; 480 | } 481 | 482 | // Needed as a compare functor for sets of const char 483 | struct CharPointerComparator { 484 | bool operator()(const char *str1, const char *str2) const { 485 | return strcmp(str1, str2) < 0; 486 | } 487 | }; 488 | 489 | // Note: this can be an expensive call, as we sort out duplicates in MultiDex files. 490 | static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie) { 491 | const OatFile* oat_file = nullptr; 492 | std::vector dex_files; 493 | if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 494 | DCHECK(env->ExceptionCheck()); 495 | return nullptr; 496 | } 497 | 498 | // Push all class descriptors into a set. Use set instead of unordered_set as we want to 499 | // retrieve all in the end. 500 | std::set descriptors; 501 | for (auto& dex_file : dex_files) { 502 | for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) { 503 | const dex::ClassDef& class_def = dex_file->GetClassDef(i); 504 | const char* descriptor = dex_file->GetClassDescriptor(class_def); 505 | descriptors.insert(descriptor); 506 | } 507 | } 508 | 509 | // Now create output array and copy the set into it. 510 | jobjectArray result = env->NewObjectArray(descriptors.size(), 511 | WellKnownClasses::java_lang_String, 512 | nullptr); 513 | if (result != nullptr) { 514 | auto it = descriptors.begin(); 515 | auto it_end = descriptors.end(); 516 | jsize i = 0; 517 | for (; it != it_end; it++, ++i) { 518 | std::string descriptor(DescriptorToDot(*it)); 519 | ScopedLocalRef jdescriptor(env, env->NewStringUTF(descriptor.c_str())); 520 | if (jdescriptor.get() == nullptr) { 521 | return nullptr; 522 | } 523 | env->SetObjectArrayElement(result, i, jdescriptor.get()); 524 | } 525 | } 526 | return result; 527 | } 528 | 529 | //addfunction 将ava的Method转换成ArtMethod。然后主动调用 530 | static void DexFile_fartextMethodCode(JNIEnv* env, jclass,jobject method) { 531 | if(method!=nullptr) 532 | { 533 | ArtMethod* proxy_method = jobject2ArtMethod(env, method); 534 | fartextInvoke(proxy_method); 535 | } 536 | 537 | return; 538 | } 539 | 540 | static jint GetDexOptNeeded(JNIEnv* env, 541 | const char* filename, 542 | const char* instruction_set, 543 | const char* compiler_filter_name, 544 | const char* class_loader_context, 545 | bool profile_changed, 546 | bool downgrade) { 547 | if ((filename == nullptr) || !OS::FileExists(filename)) { 548 | LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist"; 549 | ScopedLocalRef fnfe(env, env->FindClass("java/io/FileNotFoundException")); 550 | const char* message = (filename == nullptr) ? "" : filename; 551 | env->ThrowNew(fnfe.get(), message); 552 | return -1; 553 | } 554 | 555 | const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set); 556 | if (target_instruction_set == InstructionSet::kNone) { 557 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 558 | std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set)); 559 | env->ThrowNew(iae.get(), message.c_str()); 560 | return -1; 561 | } 562 | 563 | CompilerFilter::Filter filter; 564 | if (!CompilerFilter::ParseCompilerFilter(compiler_filter_name, &filter)) { 565 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 566 | std::string message(StringPrintf("Compiler filter %s is invalid.", compiler_filter_name)); 567 | env->ThrowNew(iae.get(), message.c_str()); 568 | return -1; 569 | } 570 | 571 | std::unique_ptr context = nullptr; 572 | if (class_loader_context != nullptr) { 573 | context = ClassLoaderContext::Create(class_loader_context); 574 | 575 | if (context == nullptr) { 576 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 577 | std::string message(StringPrintf("Class loader context '%s' is invalid.", 578 | class_loader_context)); 579 | env->ThrowNew(iae.get(), message.c_str()); 580 | return -1; 581 | } 582 | } 583 | 584 | // TODO: Verify the dex location is well formed, and throw an IOException if 585 | // not? 586 | 587 | OatFileAssistant oat_file_assistant(filename, target_instruction_set, false); 588 | 589 | // Always treat elements of the bootclasspath as up-to-date. 590 | if (oat_file_assistant.IsInBootClassPath()) { 591 | return OatFileAssistant::kNoDexOptNeeded; 592 | } 593 | 594 | return oat_file_assistant.GetDexOptNeeded(filter, 595 | profile_changed, 596 | downgrade, 597 | context.get()); 598 | } 599 | 600 | static jstring DexFile_getDexFileStatus(JNIEnv* env, 601 | jclass, 602 | jstring javaFilename, 603 | jstring javaInstructionSet) { 604 | ScopedUtfChars filename(env, javaFilename); 605 | if (env->ExceptionCheck()) { 606 | return nullptr; 607 | } 608 | 609 | ScopedUtfChars instruction_set(env, javaInstructionSet); 610 | if (env->ExceptionCheck()) { 611 | return nullptr; 612 | } 613 | 614 | const InstructionSet target_instruction_set = GetInstructionSetFromString( 615 | instruction_set.c_str()); 616 | if (target_instruction_set == InstructionSet::kNone) { 617 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 618 | std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 619 | env->ThrowNew(iae.get(), message.c_str()); 620 | return nullptr; 621 | } 622 | 623 | OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set, 624 | /* load_executable= */ false); 625 | return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str()); 626 | } 627 | 628 | // Return an array specifying the optimization status of the given file. 629 | // The array specification is [compiler_filter, compiler_reason]. 630 | static jobjectArray DexFile_getDexFileOptimizationStatus(JNIEnv* env, 631 | jclass, 632 | jstring javaFilename, 633 | jstring javaInstructionSet) { 634 | ScopedUtfChars filename(env, javaFilename); 635 | if (env->ExceptionCheck()) { 636 | return nullptr; 637 | } 638 | 639 | ScopedUtfChars instruction_set(env, javaInstructionSet); 640 | if (env->ExceptionCheck()) { 641 | return nullptr; 642 | } 643 | 644 | const InstructionSet target_instruction_set = GetInstructionSetFromString( 645 | instruction_set.c_str()); 646 | if (target_instruction_set == InstructionSet::kNone) { 647 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 648 | std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 649 | env->ThrowNew(iae.get(), message.c_str()); 650 | return nullptr; 651 | } 652 | 653 | std::string compilation_filter; 654 | std::string compilation_reason; 655 | OatFileAssistant::GetOptimizationStatus( 656 | filename.c_str(), target_instruction_set, &compilation_filter, &compilation_reason); 657 | 658 | ScopedLocalRef j_compilation_filter(env, env->NewStringUTF(compilation_filter.c_str())); 659 | if (j_compilation_filter.get() == nullptr) { 660 | return nullptr; 661 | } 662 | ScopedLocalRef j_compilation_reason(env, env->NewStringUTF(compilation_reason.c_str())); 663 | if (j_compilation_reason.get() == nullptr) { 664 | return nullptr; 665 | } 666 | 667 | // Now create output array and copy the set into it. 668 | jobjectArray result = env->NewObjectArray(2, 669 | WellKnownClasses::java_lang_String, 670 | nullptr); 671 | env->SetObjectArrayElement(result, 0, j_compilation_filter.get()); 672 | env->SetObjectArrayElement(result, 1, j_compilation_reason.get()); 673 | 674 | return result; 675 | } 676 | 677 | static jint DexFile_getDexOptNeeded(JNIEnv* env, 678 | jclass, 679 | jstring javaFilename, 680 | jstring javaInstructionSet, 681 | jstring javaTargetCompilerFilter, 682 | jstring javaClassLoaderContext, 683 | jboolean newProfile, 684 | jboolean downgrade) { 685 | ScopedUtfChars filename(env, javaFilename); 686 | if (env->ExceptionCheck()) { 687 | return -1; 688 | } 689 | 690 | ScopedUtfChars instruction_set(env, javaInstructionSet); 691 | if (env->ExceptionCheck()) { 692 | return -1; 693 | } 694 | 695 | ScopedUtfChars target_compiler_filter(env, javaTargetCompilerFilter); 696 | if (env->ExceptionCheck()) { 697 | return -1; 698 | } 699 | 700 | NullableScopedUtfChars class_loader_context(env, javaClassLoaderContext); 701 | if (env->ExceptionCheck()) { 702 | return -1; 703 | } 704 | 705 | return GetDexOptNeeded(env, 706 | filename.c_str(), 707 | instruction_set.c_str(), 708 | target_compiler_filter.c_str(), 709 | class_loader_context.c_str(), 710 | newProfile == JNI_TRUE, 711 | downgrade == JNI_TRUE); 712 | } 713 | 714 | // public API 715 | static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { 716 | ScopedUtfChars filename_utf(env, javaFilename); 717 | if (env->ExceptionCheck()) { 718 | return JNI_FALSE; 719 | } 720 | 721 | const char* filename = filename_utf.c_str(); 722 | if ((filename == nullptr) || !OS::FileExists(filename)) { 723 | LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename << "' does not exist"; 724 | ScopedLocalRef fnfe(env, env->FindClass("java/io/FileNotFoundException")); 725 | const char* message = (filename == nullptr) ? "" : filename; 726 | env->ThrowNew(fnfe.get(), message); 727 | return JNI_FALSE; 728 | } 729 | 730 | OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false); 731 | return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE; 732 | } 733 | 734 | static jboolean DexFile_isValidCompilerFilter(JNIEnv* env, 735 | jclass javeDexFileClass ATTRIBUTE_UNUSED, 736 | jstring javaCompilerFilter) { 737 | ScopedUtfChars compiler_filter(env, javaCompilerFilter); 738 | if (env->ExceptionCheck()) { 739 | return -1; 740 | } 741 | 742 | CompilerFilter::Filter filter; 743 | return CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) 744 | ? JNI_TRUE : JNI_FALSE; 745 | } 746 | 747 | static jboolean DexFile_isProfileGuidedCompilerFilter(JNIEnv* env, 748 | jclass javeDexFileClass ATTRIBUTE_UNUSED, 749 | jstring javaCompilerFilter) { 750 | ScopedUtfChars compiler_filter(env, javaCompilerFilter); 751 | if (env->ExceptionCheck()) { 752 | return -1; 753 | } 754 | 755 | CompilerFilter::Filter filter; 756 | if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 757 | return JNI_FALSE; 758 | } 759 | return CompilerFilter::DependsOnProfile(filter) ? JNI_TRUE : JNI_FALSE; 760 | } 761 | 762 | static jstring DexFile_getNonProfileGuidedCompilerFilter(JNIEnv* env, 763 | jclass javeDexFileClass ATTRIBUTE_UNUSED, 764 | jstring javaCompilerFilter) { 765 | ScopedUtfChars compiler_filter(env, javaCompilerFilter); 766 | if (env->ExceptionCheck()) { 767 | return nullptr; 768 | } 769 | 770 | CompilerFilter::Filter filter; 771 | if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 772 | return javaCompilerFilter; 773 | } 774 | 775 | CompilerFilter::Filter new_filter = CompilerFilter::GetNonProfileDependentFilterFrom(filter); 776 | 777 | // Filter stayed the same, return input. 778 | if (filter == new_filter) { 779 | return javaCompilerFilter; 780 | } 781 | 782 | // Create a new string object and return. 783 | std::string new_filter_str = CompilerFilter::NameOfFilter(new_filter); 784 | return env->NewStringUTF(new_filter_str.c_str()); 785 | } 786 | 787 | static jstring DexFile_getSafeModeCompilerFilter(JNIEnv* env, 788 | jclass javeDexFileClass ATTRIBUTE_UNUSED, 789 | jstring javaCompilerFilter) { 790 | ScopedUtfChars compiler_filter(env, javaCompilerFilter); 791 | if (env->ExceptionCheck()) { 792 | return nullptr; 793 | } 794 | 795 | CompilerFilter::Filter filter; 796 | if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 797 | return javaCompilerFilter; 798 | } 799 | 800 | CompilerFilter::Filter new_filter = CompilerFilter::GetSafeModeFilterFrom(filter); 801 | 802 | // Filter stayed the same, return input. 803 | if (filter == new_filter) { 804 | return javaCompilerFilter; 805 | } 806 | 807 | // Create a new string object and return. 808 | std::string new_filter_str = CompilerFilter::NameOfFilter(new_filter); 809 | return env->NewStringUTF(new_filter_str.c_str()); 810 | } 811 | 812 | static jboolean DexFile_isBackedByOatFile(JNIEnv* env, jclass, jobject cookie) { 813 | const OatFile* oat_file = nullptr; 814 | std::vector dex_files; 815 | if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 816 | DCHECK(env->ExceptionCheck()); 817 | return false; 818 | } 819 | return oat_file != nullptr; 820 | } 821 | 822 | static jobjectArray DexFile_getDexFileOutputPaths(JNIEnv* env, 823 | jclass, 824 | jstring javaFilename, 825 | jstring javaInstructionSet) { 826 | ScopedUtfChars filename(env, javaFilename); 827 | if (env->ExceptionCheck()) { 828 | return nullptr; 829 | } 830 | 831 | ScopedUtfChars instruction_set(env, javaInstructionSet); 832 | if (env->ExceptionCheck()) { 833 | return nullptr; 834 | } 835 | 836 | const InstructionSet target_instruction_set = GetInstructionSetFromString( 837 | instruction_set.c_str()); 838 | if (target_instruction_set == InstructionSet::kNone) { 839 | ScopedLocalRef iae(env, env->FindClass("java/lang/IllegalArgumentException")); 840 | std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 841 | env->ThrowNew(iae.get(), message.c_str()); 842 | return nullptr; 843 | } 844 | 845 | OatFileAssistant oat_file_assistant(filename.c_str(), 846 | target_instruction_set, 847 | /* load_executable= */ false); 848 | 849 | std::unique_ptr best_oat_file = oat_file_assistant.GetBestOatFile(); 850 | if (best_oat_file == nullptr) { 851 | return nullptr; 852 | } 853 | 854 | std::string oat_filename = best_oat_file->GetLocation(); 855 | std::string vdex_filename = GetVdexFilename(best_oat_file->GetLocation()); 856 | 857 | ScopedLocalRef jvdexFilename(env, env->NewStringUTF(vdex_filename.c_str())); 858 | if (jvdexFilename.get() == nullptr) { 859 | return nullptr; 860 | } 861 | ScopedLocalRef joatFilename(env, env->NewStringUTF(oat_filename.c_str())); 862 | if (joatFilename.get() == nullptr) { 863 | return nullptr; 864 | } 865 | 866 | // Now create output array and copy the set into it. 867 | jobjectArray result = env->NewObjectArray(2, 868 | WellKnownClasses::java_lang_String, 869 | nullptr); 870 | env->SetObjectArrayElement(result, 0, jvdexFilename.get()); 871 | env->SetObjectArrayElement(result, 1, joatFilename.get()); 872 | 873 | return result; 874 | } 875 | 876 | static jlong DexFile_getStaticSizeOfDexFile(JNIEnv* env, jclass, jobject cookie) { 877 | const OatFile* oat_file = nullptr; 878 | std::vector dex_files; 879 | if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 880 | DCHECK(env->ExceptionCheck()); 881 | return 0; 882 | } 883 | 884 | uint64_t file_size = 0; 885 | for (auto& dex_file : dex_files) { 886 | if (dex_file) { 887 | file_size += dex_file->GetHeader().file_size_; 888 | } 889 | } 890 | return static_cast(file_size); 891 | } 892 | 893 | static void DexFile_setTrusted(JNIEnv* env, jclass, jobject j_cookie) { 894 | Runtime* runtime = Runtime::Current(); 895 | ScopedObjectAccess soa(env); 896 | 897 | // Currently only allow this for debuggable apps. 898 | if (!runtime->IsJavaDebuggable()) { 899 | ThrowSecurityException("Can't exempt class, process is not debuggable."); 900 | return; 901 | } 902 | 903 | std::vector dex_files; 904 | const OatFile* oat_file; 905 | if (!ConvertJavaArrayToDexFiles(env, j_cookie, dex_files, oat_file)) { 906 | Thread::Current()->AssertPendingException(); 907 | return; 908 | } 909 | 910 | // Assign core platform domain as the dex files are allowed to access all the other domains. 911 | for (const DexFile* dex_file : dex_files) { 912 | const_cast(dex_file)->SetHiddenapiDomain(hiddenapi::Domain::kCorePlatform); 913 | } 914 | } 915 | 916 | static JNINativeMethod gMethods[] = { 917 | NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"), 918 | NATIVE_METHOD(DexFile, 919 | defineClassNative, 920 | "(Ljava/lang/String;" 921 | "Ljava/lang/ClassLoader;" 922 | "Ljava/lang/Object;" 923 | "Ldalvik/system/DexFile;" 924 | ")Ljava/lang/Class;"), 925 | NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"), 926 | NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"), 927 | NATIVE_METHOD(DexFile, getDexOptNeeded, 928 | "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)I"), 929 | NATIVE_METHOD(DexFile, openDexFileNative, 930 | "(Ljava/lang/String;" 931 | "Ljava/lang/String;" 932 | "I" 933 | "Ljava/lang/ClassLoader;" 934 | "[Ldalvik/system/DexPathList$Element;" 935 | ")Ljava/lang/Object;"), 936 | NATIVE_METHOD(DexFile, openInMemoryDexFilesNative, 937 | "([Ljava/nio/ByteBuffer;" 938 | "[[B" 939 | "[I" 940 | "[I" 941 | "Ljava/lang/ClassLoader;" 942 | "[Ldalvik/system/DexPathList$Element;" 943 | ")Ljava/lang/Object;"), 944 | NATIVE_METHOD(DexFile, getClassLoaderContext, 945 | "(Ljava/lang/ClassLoader;" 946 | "[Ldalvik/system/DexPathList$Element;" 947 | ")Ljava/lang/String;"), 948 | NATIVE_METHOD(DexFile, verifyInBackgroundNative, 949 | "(Ljava/lang/Object;" 950 | "Ljava/lang/ClassLoader;" 951 | "Ljava/lang/String;" 952 | ")V"), 953 | NATIVE_METHOD(DexFile, isValidCompilerFilter, "(Ljava/lang/String;)Z"), 954 | NATIVE_METHOD(DexFile, isProfileGuidedCompilerFilter, "(Ljava/lang/String;)Z"), 955 | NATIVE_METHOD(DexFile, 956 | getNonProfileGuidedCompilerFilter, 957 | "(Ljava/lang/String;)Ljava/lang/String;"), 958 | NATIVE_METHOD(DexFile, 959 | getSafeModeCompilerFilter, 960 | "(Ljava/lang/String;)Ljava/lang/String;"), 961 | NATIVE_METHOD(DexFile, isBackedByOatFile, "(Ljava/lang/Object;)Z"), 962 | NATIVE_METHOD(DexFile, getDexFileStatus, 963 | "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), 964 | NATIVE_METHOD(DexFile, getDexFileOutputPaths, 965 | "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), 966 | NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), 967 | NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, 968 | "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), 969 | NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V"), 970 | //add 971 | NATIVE_METHOD(DexFile, fartextMethodCode, 972 | "(Ljava/lang/Object;)V") 973 | //add end 974 | }; 975 | 976 | void register_dalvik_system_DexFile(JNIEnv* env) { 977 | REGISTER_NATIVE_METHODS("dalvik/system/DexFile"); 978 | } 979 | 980 | } // namespace art 981 | -------------------------------------------------------------------------------- /art/runtime/native/java_lang_reflect_Method.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 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 "java_lang_reflect_Method.h" 18 | 19 | #include "nativehelper/jni_macros.h" 20 | 21 | #include "art_method-inl.h" 22 | #include "base/enums.h" 23 | #include "class_linker-inl.h" 24 | #include "class_linker.h" 25 | #include "class_root.h" 26 | #include "dex/dex_file_annotations.h" 27 | #include "jni/jni_internal.h" 28 | #include "mirror/class-inl.h" 29 | #include "mirror/object-inl.h" 30 | #include "mirror/object_array-alloc-inl.h" 31 | #include "native_util.h" 32 | #include "reflection.h" 33 | #include "scoped_fast_native_object_access-inl.h" 34 | #include "well_known_classes.h" 35 | 36 | namespace art { 37 | 38 | //add 39 | extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod) { 40 | ScopedFastNativeObjectAccess soa(env); 41 | ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); 42 | return method; 43 | } 44 | //add end 45 | 46 | static jobject Method_getDefaultValue(JNIEnv* env, jobject javaMethod) { 47 | ScopedFastNativeObjectAccess soa(env); 48 | ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); 49 | if (!method->GetDeclaringClass()->IsAnnotation()) { 50 | return nullptr; 51 | } 52 | return soa.AddLocalReference(annotations::GetAnnotationDefaultValue(method)); 53 | } 54 | 55 | static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { 56 | ScopedFastNativeObjectAccess soa(env); 57 | ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); 58 | if (method->GetDeclaringClass()->IsProxyClass()) { 59 | ObjPtr klass = method->GetDeclaringClass(); 60 | int throws_index = -1; 61 | size_t i = 0; 62 | for (const auto& m : klass->GetDeclaredVirtualMethods(kRuntimePointerSize)) { 63 | if (&m == method) { 64 | throws_index = i; 65 | break; 66 | } 67 | ++i; 68 | } 69 | CHECK_NE(throws_index, -1); 70 | ObjPtr> declared_exceptions = 71 | klass->GetProxyThrows()->Get(throws_index); 72 | return soa.AddLocalReference(declared_exceptions->Clone(soa.Self())); 73 | } else { 74 | ObjPtr> result_array = 75 | annotations::GetExceptionTypesForMethod(method); 76 | if (result_array == nullptr) { 77 | // Return an empty array instead of a null pointer 78 | ObjPtr class_array_class = GetClassRoot>(); 79 | DCHECK(class_array_class != nullptr); 80 | ObjPtr> empty_array = 81 | mirror::ObjectArray::Alloc(soa.Self(), class_array_class, 0); 82 | return soa.AddLocalReference(empty_array); 83 | } else { 84 | return soa.AddLocalReference(result_array); 85 | } 86 | } 87 | } 88 | 89 | static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, 90 | jobjectArray javaArgs) { 91 | ScopedFastNativeObjectAccess soa(env); 92 | return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs); 93 | } 94 | 95 | static JNINativeMethod gMethods[] = { 96 | FAST_NATIVE_METHOD(Method, getDefaultValue, "()Ljava/lang/Object;"), 97 | FAST_NATIVE_METHOD(Method, getExceptionTypes, "()[Ljava/lang/Class;"), 98 | FAST_NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"), 99 | }; 100 | 101 | void register_java_lang_reflect_Method(JNIEnv* env) { 102 | REGISTER_NATIVE_METHODS("java/lang/reflect/Method"); 103 | } 104 | 105 | } // namespace art 106 | -------------------------------------------------------------------------------- /frameworks/base/core/java/cn/mik/Fartext.java: -------------------------------------------------------------------------------- 1 | package cn.mik; 2 | 3 | import android.app.ActivityThread; 4 | import android.app.Application; 5 | import android.util.Log; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.FileReader; 9 | import java.lang.reflect.Constructor; 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class Fartext { 18 | //为了反射封装,根据类名和字段名,反射获取字段 19 | public static Field getClassField(ClassLoader classloader, String class_name, 20 | String filedName) { 21 | 22 | try { 23 | Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name); 24 | Field field = obj_class.getDeclaredField(filedName); 25 | field.setAccessible(true); 26 | return field; 27 | } catch (SecurityException e) { 28 | e.printStackTrace(); 29 | } catch (NoSuchFieldException e) { 30 | e.printStackTrace(); 31 | } catch (IllegalArgumentException e) { 32 | e.printStackTrace(); 33 | } catch (ClassNotFoundException e) { 34 | e.printStackTrace(); 35 | } 36 | return null; 37 | 38 | } 39 | 40 | public static Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj, 41 | String filedName) { 42 | 43 | try { 44 | Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name); 45 | Field field = obj_class.getDeclaredField(filedName); 46 | field.setAccessible(true); 47 | Object result = null; 48 | result = field.get(obj); 49 | return result; 50 | //field.setAccessible(true); 51 | //return field; 52 | } catch (SecurityException e) { 53 | e.printStackTrace(); 54 | } catch (NoSuchFieldException e) { 55 | e.printStackTrace(); 56 | } catch (IllegalArgumentException e) { 57 | e.printStackTrace(); 58 | } catch (ClassNotFoundException e) { 59 | e.printStackTrace(); 60 | } catch (IllegalAccessException e) { 61 | e.printStackTrace(); 62 | } 63 | return null; 64 | 65 | } 66 | 67 | public static Object invokeStaticMethod(String class_name, 68 | String method_name, Class[] pareTyple, Object[] pareVaules) { 69 | 70 | try { 71 | Class obj_class = Class.forName(class_name); 72 | Method method = obj_class.getMethod(method_name, pareTyple); 73 | return method.invoke(null, pareVaules); 74 | } catch (SecurityException e) { 75 | e.printStackTrace(); 76 | } catch (IllegalArgumentException e) { 77 | e.printStackTrace(); 78 | } catch (IllegalAccessException e) { 79 | e.printStackTrace(); 80 | } catch (NoSuchMethodException e) { 81 | e.printStackTrace(); 82 | } catch (InvocationTargetException e) { 83 | e.printStackTrace(); 84 | } catch (ClassNotFoundException e) { 85 | e.printStackTrace(); 86 | } 87 | return null; 88 | 89 | } 90 | 91 | public static Object getFieldObject(String class_name, Object obj, 92 | String filedName) { 93 | try { 94 | Class obj_class = Class.forName(class_name); 95 | Field field = obj_class.getDeclaredField(filedName); 96 | field.setAccessible(true); 97 | return field.get(obj); 98 | } catch (SecurityException e) { 99 | e.printStackTrace(); 100 | } catch (NoSuchFieldException e) { 101 | e.printStackTrace(); 102 | } catch (IllegalArgumentException e) { 103 | e.printStackTrace(); 104 | } catch (IllegalAccessException e) { 105 | e.printStackTrace(); 106 | } catch (ClassNotFoundException e) { 107 | e.printStackTrace(); 108 | } catch (NullPointerException e) { 109 | e.printStackTrace(); 110 | } 111 | return null; 112 | 113 | } 114 | 115 | public static Application getCurrentApplication(){ 116 | Object currentActivityThread = invokeStaticMethod( 117 | "android.app.ActivityThread", "currentActivityThread", 118 | new Class[]{}, new Object[]{}); 119 | Object mBoundApplication = getFieldObject( 120 | "android.app.ActivityThread", currentActivityThread, 121 | "mBoundApplication"); 122 | Application mInitialApplication = (Application) getFieldObject("android.app.ActivityThread", 123 | currentActivityThread, "mInitialApplication"); 124 | Object loadedApkInfo = getFieldObject( 125 | "android.app.ActivityThread$AppBindData", 126 | mBoundApplication, "info"); 127 | Application mApplication = (Application) getFieldObject("android.app.LoadedApk", loadedApkInfo, "mApplication"); 128 | return mApplication; 129 | } 130 | 131 | public static ClassLoader getClassloader() { 132 | ClassLoader resultClassloader = null; 133 | Object currentActivityThread = invokeStaticMethod( 134 | "android.app.ActivityThread", "currentActivityThread", 135 | new Class[]{}, new Object[]{}); 136 | Object mBoundApplication = getFieldObject( 137 | "android.app.ActivityThread", currentActivityThread, 138 | "mBoundApplication"); 139 | Application mInitialApplication = (Application) getFieldObject("android.app.ActivityThread", 140 | currentActivityThread, "mInitialApplication"); 141 | Object loadedApkInfo = getFieldObject( 142 | "android.app.ActivityThread$AppBindData", 143 | mBoundApplication, "info"); 144 | Application mApplication = (Application) getFieldObject("android.app.LoadedApk", loadedApkInfo, "mApplication"); 145 | Log.e("fartext", "go into app->" + "packagename:" + mApplication.getPackageName()); 146 | resultClassloader = mApplication.getClassLoader(); 147 | return resultClassloader; 148 | } 149 | //取指定类的所有构造函数,和所有函数,使用dumpMethodCode函数来把这些函数给保存出来 150 | public static void loadClassAndInvoke(ClassLoader appClassloader, String eachclassname, Method dumpMethodCode_method) { 151 | Class resultclass = null; 152 | Log.e("fartext", "go into loadClassAndInvoke->" + "classname:" + eachclassname); 153 | try { 154 | resultclass = appClassloader.loadClass(eachclassname); 155 | } catch (Exception e) { 156 | e.printStackTrace(); 157 | return; 158 | } catch (Error e) { 159 | e.printStackTrace(); 160 | return; 161 | } 162 | if (resultclass != null) { 163 | try { 164 | Constructor cons[] = resultclass.getDeclaredConstructors(); 165 | for (Constructor constructor : cons) { 166 | if (dumpMethodCode_method != null) { 167 | try { 168 | if(constructor.getName().contains("cn.mik.")){ 169 | continue; 170 | } 171 | Log.e("fartext", "classname:" + eachclassname+ " constructor->invoke "+constructor.getName()); 172 | dumpMethodCode_method.invoke(null, constructor); 173 | } catch (Exception e) { 174 | e.printStackTrace(); 175 | continue; 176 | } catch (Error e) { 177 | e.printStackTrace(); 178 | continue; 179 | } 180 | } else { 181 | Log.e("fartext", "dumpMethodCode_method is null "); 182 | } 183 | 184 | } 185 | } catch (Exception e) { 186 | e.printStackTrace(); 187 | } catch (Error e) { 188 | e.printStackTrace(); 189 | } 190 | try { 191 | Method[] methods = resultclass.getDeclaredMethods(); 192 | if (methods != null) { 193 | Log.e("fartext", "classname:" + eachclassname+ " start invoke"); 194 | for (Method m : methods) { 195 | if (dumpMethodCode_method != null) { 196 | try { 197 | if(m.getName().contains("cn.mik.")){ 198 | continue; 199 | } 200 | Log.e("fartext", "classname:" + eachclassname+ " method->invoke:" + m.getName()); 201 | dumpMethodCode_method.invoke(null, m); 202 | } catch (Exception e) { 203 | e.printStackTrace(); 204 | continue; 205 | } catch (Error e) { 206 | e.printStackTrace(); 207 | continue; 208 | } 209 | } else { 210 | Log.e("fartext", "dumpMethodCode_method is null "); 211 | } 212 | } 213 | Log.e("fartext", "go into loadClassAndInvoke->" + "classname:" + eachclassname+ " end invoke"); 214 | } 215 | } catch (Exception e) { 216 | e.printStackTrace(); 217 | } catch (Error e) { 218 | e.printStackTrace(); 219 | } 220 | } 221 | } 222 | 223 | //根据classLoader->pathList->dexElements拿到dexFile 224 | //然后拿到mCookie后,使用getClassNameList获取到所有类名。 225 | //loadClassAndInvoke处理所有类名导出所有函数 226 | //dumpMethodCode这个函数是fart自己加在DexFile中的 227 | public static void fartWithClassLoader(ClassLoader appClassloader) { 228 | Log.e("fartext", "fartWithClassLoader "+appClassloader.toString()); 229 | List dexFilesArray = new ArrayList(); 230 | Field paist_Field = (Field) getClassField(appClassloader, "dalvik.system.BaseDexClassLoader", "pathList"); 231 | Object pathList_object = getFieldObject("dalvik.system.BaseDexClassLoader", appClassloader, "pathList"); 232 | Object[] ElementsArray = (Object[]) getFieldObject("dalvik.system.DexPathList", pathList_object, "dexElements"); 233 | Field dexFile_fileField = null; 234 | try { 235 | dexFile_fileField = (Field) getClassField(appClassloader, "dalvik.system.DexPathList$Element", "dexFile"); 236 | } catch (Exception e) { 237 | e.printStackTrace(); 238 | } catch (Error e) { 239 | e.printStackTrace(); 240 | } 241 | Class DexFileClazz = null; 242 | try { 243 | DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile"); 244 | } catch (Exception e) { 245 | e.printStackTrace(); 246 | } catch (Error e) { 247 | e.printStackTrace(); 248 | } 249 | Method getClassNameList_method = null; 250 | Method defineClass_method = null; 251 | Method dumpDexFile_method = null; 252 | Method dumpMethodCode_method = null; 253 | 254 | for (Method field : DexFileClazz.getDeclaredMethods()) { 255 | if (field.getName().equals("getClassNameList")) { 256 | getClassNameList_method = field; 257 | getClassNameList_method.setAccessible(true); 258 | } 259 | if (field.getName().equals("defineClassNative")) { 260 | defineClass_method = field; 261 | defineClass_method.setAccessible(true); 262 | } 263 | if (field.getName().equals("dumpDexFile")) { 264 | dumpDexFile_method = field; 265 | dumpDexFile_method.setAccessible(true); 266 | } 267 | if (field.getName().equals("fartextMethodCode")) { 268 | dumpMethodCode_method = field; 269 | dumpMethodCode_method.setAccessible(true); 270 | } 271 | } 272 | Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie"); 273 | Log.e("fartext->methods", "dalvik.system.DexPathList.ElementsArray.length:" + ElementsArray.length); 274 | for (int j = 0; j < ElementsArray.length; j++) { 275 | Object element = ElementsArray[j]; 276 | Object dexfile = null; 277 | try { 278 | dexfile = (Object) dexFile_fileField.get(element); 279 | } catch (Exception e) { 280 | e.printStackTrace(); 281 | } catch (Error e) { 282 | e.printStackTrace(); 283 | } 284 | if (dexfile == null) { 285 | Log.e("fartext", "dexfile is null"); 286 | continue; 287 | } 288 | if (dexfile != null) { 289 | dexFilesArray.add(dexfile); 290 | Object mcookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mCookie"); 291 | if (mcookie == null) { 292 | Object mInternalCookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mInternalCookie"); 293 | if(mInternalCookie!=null) 294 | { 295 | mcookie=mInternalCookie; 296 | }else{ 297 | Log.e("fartext->err", "get mInternalCookie is null"); 298 | continue; 299 | } 300 | 301 | } 302 | String[] classnames = null; 303 | try { 304 | classnames = (String[]) getClassNameList_method.invoke(dexfile, mcookie); 305 | } catch (Exception e) { 306 | e.printStackTrace(); 307 | continue; 308 | } catch (Error e) { 309 | e.printStackTrace(); 310 | continue; 311 | } 312 | if (classnames != null) { 313 | Log.e("fartext", "all classes "+String.join(",",classnames)); 314 | for (String eachclassname : classnames) { 315 | loadClassAndInvoke(appClassloader, eachclassname, dumpMethodCode_method); 316 | } 317 | } 318 | 319 | } 320 | } 321 | return; 322 | } 323 | 324 | public static void fart() { 325 | Log.e("fartext", "fart"); 326 | ClassLoader appClassloader = getClassloader(); 327 | if(appClassloader==null){ 328 | Log.e("fartext", "appClassloader is null"); 329 | return; 330 | } 331 | ClassLoader tmpClassloader=appClassloader; 332 | ClassLoader parentClassloader=appClassloader.getParent(); 333 | if(appClassloader.toString().indexOf("java.lang.BootClassLoader")==-1) 334 | { 335 | fartWithClassLoader(appClassloader); 336 | } 337 | while(parentClassloader!=null){ 338 | if(parentClassloader.toString().indexOf("java.lang.BootClassLoader")==-1) 339 | { 340 | fartWithClassLoader(parentClassloader); 341 | } 342 | tmpClassloader=parentClassloader; 343 | parentClassloader=parentClassloader.getParent(); 344 | } 345 | } 346 | 347 | public static boolean shouldUnpack() { 348 | boolean should_unpack = false; 349 | String processName = ActivityThread.currentProcessName(); 350 | BufferedReader br = null; 351 | String configPath="/data/local/tmp/fext.config"; 352 | Log.e("fartext", "shouldUnpack processName:"+processName); 353 | try { 354 | br = new BufferedReader(new FileReader(configPath)); 355 | String line; 356 | while ((line = br.readLine()) != null) { 357 | if (processName.equals(line)) { 358 | should_unpack = true; 359 | break; 360 | } 361 | } 362 | br.close(); 363 | } 364 | catch (Exception ex) { 365 | Log.e("fartext", "shouldUnpack err:"+ex.getMessage()); 366 | } 367 | return should_unpack; 368 | } 369 | 370 | public static String getClassList() { 371 | String processName = ActivityThread.currentProcessName(); 372 | BufferedReader br = null; 373 | String configPath="/data/local/tmp/"+processName; 374 | Log.e("fartext", "getClassList processName:"+processName); 375 | StringBuilder sb=new StringBuilder(); 376 | try { 377 | br = new BufferedReader(new FileReader(configPath)); 378 | String line; 379 | while ((line = br.readLine()) != null) { 380 | 381 | if(line.length()>=2){ 382 | sb.append(line+"\n"); 383 | } 384 | } 385 | br.close(); 386 | } 387 | catch (Exception ex) { 388 | Log.e("fartext", "getClassList err:"+ex.getMessage()); 389 | return ""; 390 | } 391 | return sb.toString(); 392 | } 393 | 394 | public static void fartWithClassList(String classlist){ 395 | ClassLoader appClassloader = getClassloader(); 396 | if(appClassloader==null){ 397 | Log.e("fartext", "appClassloader is null"); 398 | return; 399 | } 400 | Class DexFileClazz = null; 401 | try { 402 | DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile"); 403 | } catch (Exception e) { 404 | e.printStackTrace(); 405 | } catch (Error e) { 406 | e.printStackTrace(); 407 | } 408 | Method dumpMethodCode_method = null; 409 | for (Method field : DexFileClazz.getDeclaredMethods()) { 410 | if (field.getName().equals("fartextMethodCode")) { 411 | dumpMethodCode_method = field; 412 | dumpMethodCode_method.setAccessible(true); 413 | } 414 | } 415 | String[] classes=classlist.split("\n"); 416 | for(String clsname : classes){ 417 | String line=clsname; 418 | if(line.startsWith("L")&&line.endsWith(";")&&line.contains("/")){ 419 | line=line.substring(1,line.length()-1); 420 | line=line.replace("/","."); 421 | } 422 | loadClassAndInvoke(appClassloader, line, dumpMethodCode_method); 423 | } 424 | } 425 | 426 | public static void fartthread() { 427 | 428 | if (!shouldUnpack()) { 429 | return; 430 | } 431 | String classlist=getClassList(); 432 | if(!classlist.equals("")){ 433 | fartWithClassList(classlist); 434 | return; 435 | } 436 | 437 | new Thread(new Runnable() { 438 | @Override 439 | public void run() { 440 | // TODO Auto-generated method stub 441 | try { 442 | Log.e("fartext", "start sleep......"); 443 | Thread.sleep(1 * 60 * 1000); 444 | } catch (InterruptedException e) { 445 | // TODO Auto-generated catch block 446 | e.printStackTrace(); 447 | } 448 | Log.e("fartext", "sleep over and start fart"); 449 | fart(); 450 | Log.e("fartext", "fart run over"); 451 | 452 | } 453 | }).start(); 454 | } 455 | 456 | } 457 | 458 | -------------------------------------------------------------------------------- /img/image-20210804190809645.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dqzg12300/FartExt/7179e060ddfd809a5bbff3ec5c00b07f050671a0/img/image-20210804190809645.png -------------------------------------------------------------------------------- /img/image-20210805100310939.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dqzg12300/FartExt/7179e060ddfd809a5bbff3ec5c00b07f050671a0/img/image-20210805100310939.png -------------------------------------------------------------------------------- /img/image-20210805100343385.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dqzg12300/FartExt/7179e060ddfd809a5bbff3ec5c00b07f050671a0/img/image-20210805100343385.png -------------------------------------------------------------------------------- /libcore/DexFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 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 | package dalvik.system; 18 | 19 | import android.system.ErrnoException; 20 | import dalvik.annotation.compat.UnsupportedAppUsage; 21 | import dalvik.annotation.optimization.ReachabilitySensitive; 22 | import java.io.File; 23 | import java.io.FileNotFoundException; 24 | import java.io.IOException; 25 | import java.nio.ByteBuffer; 26 | import java.util.Arrays; 27 | import java.util.Enumeration; 28 | import java.util.List; 29 | import libcore.io.Libcore; 30 | 31 | /** 32 | * Loads DEX files. This class is meant for internal use and should not be used 33 | * by applications. 34 | * 35 | * @deprecated This class should not be used directly by applications. It will hurt 36 | * performance in most cases and will lead to incorrect execution of bytecode in 37 | * the worst case. Applications should use one of the standard classloaders such 38 | * as {@link dalvik.system.PathClassLoader} instead. This API will be removed 39 | * in a future Android release. 40 | */ 41 | @libcore.api.CorePlatformApi 42 | @Deprecated 43 | public final class DexFile { 44 | /** 45 | * If close is called, mCookie becomes null but the internal cookie is preserved if the close 46 | * failed so that we can free resources in the finalizer. 47 | */ 48 | @UnsupportedAppUsage 49 | @ReachabilitySensitive 50 | private Object mCookie; 51 | 52 | @UnsupportedAppUsage 53 | private Object mInternalCookie; 54 | @UnsupportedAppUsage 55 | private final String mFileName; 56 | 57 | /** 58 | * Opens a DEX file from a given File object. 59 | * 60 | * @deprecated Applications should use one of the standard classloaders such 61 | * as {@link dalvik.system.PathClassLoader} instead. This API will be removed 62 | * in a future Android release. 63 | */ 64 | @Deprecated 65 | public DexFile(File file) throws IOException { 66 | this(file.getPath()); 67 | } 68 | /* 69 | * Private version with class loader argument. 70 | * 71 | * @param file 72 | * the File object referencing the actual DEX file 73 | * @param loader 74 | * the class loader object creating the DEX file object 75 | * @param elements 76 | * the temporary dex path list elements from DexPathList.makeElements 77 | */ 78 | DexFile(File file, ClassLoader loader, DexPathList.Element[] elements) 79 | throws IOException { 80 | this(file.getPath(), loader, elements); 81 | } 82 | 83 | /** 84 | * Opens a DEX file from a given filename. 85 | * 86 | * @deprecated Applications should use one of the standard classloaders such 87 | * as {@link dalvik.system.PathClassLoader} instead. This API will be removed 88 | * in a future Android release. 89 | */ 90 | @Deprecated 91 | public DexFile(String fileName) throws IOException { 92 | this(fileName, null, null); 93 | } 94 | 95 | /* 96 | * Private version with class loader argument. 97 | * 98 | * @param fileName 99 | * the filename of the DEX file 100 | * @param loader 101 | * the class loader creating the DEX file object 102 | * @param elements 103 | * the temporary dex path list elements from DexPathList.makeElements 104 | */ 105 | DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements) 106 | throws IOException { 107 | mCookie = openDexFile(fileName, null, 0, loader, elements); 108 | mInternalCookie = mCookie; 109 | mFileName = fileName; 110 | //System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName); 111 | } 112 | 113 | DexFile(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements) 114 | throws IOException { 115 | mCookie = openInMemoryDexFiles(bufs, loader, elements); 116 | mInternalCookie = mCookie; 117 | mFileName = null; 118 | } 119 | 120 | /** 121 | * Opens a DEX file from a given filename, using a specified file 122 | * to hold the optimized data. 123 | * 124 | * @param sourceName 125 | * Jar or APK file with "classes.dex". 126 | * @param outputName 127 | * File that will hold the optimized form of the DEX data. 128 | * @param flags 129 | * Enable optional features. 130 | * @param loader 131 | * The class loader creating the DEX file object. 132 | * @param elements 133 | * The temporary dex path list elements from DexPathList.makeElements 134 | */ 135 | private DexFile(String sourceName, String outputName, int flags, ClassLoader loader, 136 | DexPathList.Element[] elements) throws IOException { 137 | if (outputName != null) { 138 | try { 139 | String parent = new File(outputName).getParent(); 140 | if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) { 141 | throw new IllegalArgumentException("Optimized data directory " + parent 142 | + " is not owned by the current user. Shared storage cannot protect" 143 | + " your application from code injection attacks."); 144 | } 145 | } catch (ErrnoException ignored) { 146 | // assume we'll fail with a more contextual error later 147 | } 148 | } 149 | 150 | mCookie = openDexFile(sourceName, outputName, flags, loader, elements); 151 | mInternalCookie = mCookie; 152 | mFileName = sourceName; 153 | //System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName); 154 | } 155 | 156 | /** 157 | * Open a DEX file, specifying the file in which the optimized DEX 158 | * data should be written. If the optimized form exists and appears 159 | * to be current, it will be used; if not, the VM will attempt to 160 | * regenerate it. 161 | * 162 | * @deprecated Applications should use one of the standard classloaders such 163 | * as {@link dalvik.system.PathClassLoader} instead. This API will be removed 164 | * in a future Android release. 165 | */ 166 | @Deprecated 167 | static public DexFile loadDex(String sourcePathName, String outputPathName, 168 | int flags) throws IOException { 169 | 170 | /* 171 | * TODO: we may want to cache previously-opened DexFile objects. 172 | * The cache would be synchronized with close(). This would help 173 | * us avoid mapping the same DEX more than once when an app 174 | * decided to open it multiple times. In practice this may not 175 | * be a real issue. 176 | */ 177 | return loadDex(sourcePathName, outputPathName, flags, null, null); 178 | } 179 | 180 | /* 181 | * Private version of loadDex that also takes a class loader. 182 | * 183 | * @param sourcePathName 184 | * Jar or APK file with "classes.dex". (May expand this to include 185 | * "raw DEX" in the future.) 186 | * @param outputPathName 187 | * File that will hold the optimized form of the DEX data. 188 | * @param flags 189 | * Enable optional features. (Currently none defined.) 190 | * @param loader 191 | * Class loader that is aloading the DEX file. 192 | * @param elements 193 | * The temporary dex path list elements from DexPathList.makeElements 194 | * @return 195 | * A new or previously-opened DexFile. 196 | * @throws IOException 197 | * If unable to open the source or output file. 198 | */ 199 | @UnsupportedAppUsage 200 | static DexFile loadDex(String sourcePathName, String outputPathName, 201 | int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException { 202 | 203 | /* 204 | * TODO: we may want to cache previously-opened DexFile objects. 205 | * The cache would be synchronized with close(). This would help 206 | * us avoid mapping the same DEX more than once when an app 207 | * decided to open it multiple times. In practice this may not 208 | * be a real issue. 209 | */ 210 | return new DexFile(sourcePathName, outputPathName, flags, loader, elements); 211 | } 212 | 213 | /** 214 | * Gets the name of the (already opened) DEX file. 215 | * 216 | * @return the file name 217 | */ 218 | public String getName() { 219 | return mFileName; 220 | } 221 | 222 | @Override public String toString() { 223 | if (mFileName != null) { 224 | return getName(); 225 | } else { 226 | return "InMemoryDexFile[cookie=" + Arrays.toString((long[]) mCookie) + "]"; 227 | } 228 | } 229 | 230 | /** 231 | * Closes the DEX file. 232 | *

233 | * This may not be able to release all of the resources. If classes from this DEX file are 234 | * still resident, the DEX file can't be unmapped. In the case where we do not release all 235 | * the resources, close is called again in the finalizer. 236 | * 237 | * @throws IOException 238 | * if an I/O error occurs during closing the file, which 239 | * normally should not happen 240 | */ 241 | public void close() throws IOException { 242 | if (mInternalCookie != null) { 243 | if (closeDexFile(mInternalCookie)) { 244 | mInternalCookie = null; 245 | } 246 | mCookie = null; 247 | } 248 | } 249 | 250 | /** 251 | * Loads a class. Returns the class on success, or a {@code null} reference 252 | * on failure. 253 | *

254 | * If you are not calling this from a class loader, this is most likely not 255 | * going to do what you want. Use {@link Class#forName(String)} instead. 256 | *

257 | * The method does not throw {@link ClassNotFoundException} if the class 258 | * isn't found because it isn't reasonable to throw exceptions wildly every 259 | * time a class is not found in the first DEX file we look at. 260 | * 261 | * @param name 262 | * the class name, which should look like "java/lang/String" 263 | * 264 | * @param loader 265 | * the class loader that tries to load the class (in most cases 266 | * the caller of the method 267 | * 268 | * @return the {@link Class} object representing the class, or {@code null} 269 | * if the class cannot be loaded 270 | */ 271 | public Class loadClass(String name, ClassLoader loader) { 272 | String slashName = name.replace('.', '/'); 273 | return loadClassBinaryName(slashName, loader, null); 274 | } 275 | 276 | /** 277 | * See {@link #loadClass(String, ClassLoader)}. 278 | * 279 | * This takes a "binary" class name to better match ClassLoader semantics. 280 | * 281 | * @hide 282 | */ 283 | @UnsupportedAppUsage 284 | public Class loadClassBinaryName(String name, ClassLoader loader, List suppressed) { 285 | return defineClass(name, loader, mCookie, this, suppressed); 286 | } 287 | 288 | private static Class defineClass(String name, ClassLoader loader, Object cookie, 289 | DexFile dexFile, List suppressed) { 290 | Class result = null; 291 | try { 292 | result = defineClassNative(name, loader, cookie, dexFile); 293 | } catch (NoClassDefFoundError e) { 294 | if (suppressed != null) { 295 | suppressed.add(e); 296 | } 297 | } catch (ClassNotFoundException e) { 298 | if (suppressed != null) { 299 | suppressed.add(e); 300 | } 301 | } 302 | return result; 303 | } 304 | 305 | /** 306 | * Enumerate the names of the classes in this DEX file. 307 | * 308 | * @return an enumeration of names of classes contained in the DEX file, in 309 | * the usual internal form (like "java/lang/String"). 310 | */ 311 | public Enumeration entries() { 312 | return new DFEnum(this); 313 | } 314 | 315 | /* 316 | * Helper class. 317 | */ 318 | private static class DFEnum implements Enumeration { 319 | private int mIndex; 320 | @UnsupportedAppUsage 321 | private String[] mNameList; 322 | 323 | DFEnum(DexFile df) { 324 | mIndex = 0; 325 | mNameList = getClassNameList(df.mCookie); 326 | } 327 | 328 | public boolean hasMoreElements() { 329 | return (mIndex < mNameList.length); 330 | } 331 | 332 | public String nextElement() { 333 | return mNameList[mIndex++]; 334 | } 335 | } 336 | 337 | /** 338 | * Called when the class is finalized. Makes sure the DEX file is closed. 339 | * 340 | * @throws IOException 341 | * if an I/O error occurs during closing the file, which 342 | * normally should not happen 343 | */ 344 | @Override protected void finalize() throws Throwable { 345 | try { 346 | if (mInternalCookie != null && !closeDexFile(mInternalCookie)) { 347 | throw new AssertionError("Failed to close dex file in finalizer."); 348 | } 349 | mInternalCookie = null; 350 | mCookie = null; 351 | } finally { 352 | super.finalize(); 353 | } 354 | } 355 | 356 | 357 | /* 358 | * Open a DEX file. The value returned is a magic VM cookie. On 359 | * failure, an IOException is thrown. 360 | */ 361 | @UnsupportedAppUsage 362 | private static Object openDexFile(String sourceName, String outputName, int flags, 363 | ClassLoader loader, DexPathList.Element[] elements) throws IOException { 364 | // Use absolute paths to enable the use of relative paths when testing on host. 365 | return openDexFileNative(new File(sourceName).getAbsolutePath(), 366 | (outputName == null) 367 | ? null 368 | : new File(outputName).getAbsolutePath(), 369 | flags, 370 | loader, 371 | elements); 372 | } 373 | 374 | private static Object openInMemoryDexFiles(ByteBuffer[] bufs, ClassLoader loader, 375 | DexPathList.Element[] elements) throws IOException { 376 | // Preprocess the ByteBuffers for openInMemoryDexFilesNative. We extract 377 | // the backing array (non-direct buffers only) and start/end positions 378 | // so that the native method does not have to call Java methods anymore. 379 | byte[][] arrays = new byte[bufs.length][]; 380 | int[] starts = new int[bufs.length]; 381 | int[] ends = new int[bufs.length]; 382 | for (int i = 0; i < bufs.length; ++i) { 383 | arrays[i] = bufs[i].isDirect() ? null : bufs[i].array(); 384 | starts[i] = bufs[i].position(); 385 | ends[i] = bufs[i].limit(); 386 | } 387 | return openInMemoryDexFilesNative(bufs, arrays, starts, ends, loader, elements); 388 | } 389 | 390 | private static native Object openInMemoryDexFilesNative(ByteBuffer[] bufs, byte[][] arrays, 391 | int[] starts, int[] ends, ClassLoader loader, DexPathList.Element[] elements); 392 | 393 | /* 394 | * Initiates background verification of this DexFile. This is a sepearate down-call 395 | * from openDexFile and openInMemoryDexFiles because it requires the class loader's 396 | * DexPathList to have been initialized for its classes to be resolvable by ART. 397 | * DexPathList will open the dex files first, finalize `dexElements` and then call this. 398 | */ 399 | /*package*/ void verifyInBackground(ClassLoader classLoader, String classLoaderContext) { 400 | verifyInBackgroundNative(mCookie, classLoader, classLoaderContext); 401 | } 402 | 403 | private static native void verifyInBackgroundNative(Object mCookie, ClassLoader classLoader, 404 | String classLoaderContext); 405 | 406 | /*package*/ static native String getClassLoaderContext(ClassLoader classLoader, 407 | DexPathList.Element[] elements); 408 | 409 | /* 410 | * Returns true if the dex file is backed by a valid oat file. 411 | */ 412 | @UnsupportedAppUsage 413 | /*package*/ boolean isBackedByOatFile() { 414 | return isBackedByOatFile(mCookie); 415 | } 416 | 417 | /* 418 | * Set the dex file as trusted: it can access hidden APIs of the platform. 419 | */ 420 | /*package*/ void setTrusted() { 421 | setTrusted(mCookie); 422 | } 423 | 424 | /* 425 | * Returns true if we managed to close the dex file. 426 | */ 427 | private static native boolean closeDexFile(Object cookie); 428 | private static native Class defineClassNative(String name, ClassLoader loader, Object cookie, 429 | DexFile dexFile) 430 | throws ClassNotFoundException, NoClassDefFoundError; 431 | @UnsupportedAppUsage 432 | private static native String[] getClassNameList(Object cookie); 433 | 434 | //add 435 | private static native void fartextMethodCode(Object m); 436 | //add end 437 | 438 | private static native boolean isBackedByOatFile(Object cookie); 439 | private static native void setTrusted(Object cookie); 440 | /* 441 | * Open a DEX file. The value returned is a magic VM cookie. On 442 | * failure, an IOException is thrown. 443 | */ 444 | @UnsupportedAppUsage 445 | private static native Object openDexFileNative(String sourceName, String outputName, int flags, 446 | ClassLoader loader, DexPathList.Element[] elements); 447 | 448 | /** 449 | * Returns true if the VM believes that the apk/jar file is out of date 450 | * and should be passed through "dexopt" again. 451 | * 452 | * @param fileName the absolute path to the apk/jar file to examine. 453 | * @return true if dexopt should be called on the file, false otherwise. 454 | * @throws java.io.FileNotFoundException if fileName is not readable, 455 | * not a file, or not present. 456 | * @throws java.io.IOException if fileName is not a valid apk/jar file or 457 | * if problems occur while parsing it. 458 | * @throws java.lang.NullPointerException if fileName is null. 459 | */ 460 | public static native boolean isDexOptNeeded(String fileName) 461 | throws FileNotFoundException, IOException; 462 | 463 | /** 464 | * No dexopt should (or can) be done to update the apk/jar. 465 | * 466 | * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 467 | * 468 | * @hide 469 | */ 470 | @libcore.api.CorePlatformApi 471 | public static final int NO_DEXOPT_NEEDED = 0; 472 | 473 | /** 474 | * dex2oat should be run to update the apk/jar from scratch. 475 | * 476 | * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 477 | * 478 | * @hide 479 | */ 480 | public static final int DEX2OAT_FROM_SCRATCH = 1; 481 | 482 | /** 483 | * dex2oat should be run to update the apk/jar because the existing code 484 | * is out of date with respect to the boot image. 485 | * 486 | * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 487 | * 488 | * @hide 489 | */ 490 | public static final int DEX2OAT_FOR_BOOT_IMAGE = 2; 491 | 492 | /** 493 | * dex2oat should be run to update the apk/jar because the existing code 494 | * is out of date with respect to the target compiler filter. 495 | * 496 | * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 497 | * 498 | * @hide 499 | */ 500 | @libcore.api.CorePlatformApi 501 | public static final int DEX2OAT_FOR_FILTER = 3; 502 | 503 | 504 | /** 505 | * Calls {@link #getDexOptNeeded(String, String, String, String, String, boolean, boolean)} 506 | * with a null class loader context. 507 | * 508 | * TODO(ngeoffray, calin): deprecate / remove. 509 | * @hide 510 | */ 511 | public static int getDexOptNeeded(String fileName, 512 | String instructionSet, String compilerFilter, boolean newProfile, boolean downgrade) 513 | throws FileNotFoundException, IOException { 514 | return getDexOptNeeded( 515 | fileName, instructionSet, compilerFilter, null, newProfile, downgrade); 516 | } 517 | 518 | /** 519 | * Returns the VM's opinion of what kind of dexopt is needed to make the 520 | * apk/jar file up to date, where {@code targetMode} is used to indicate what 521 | * type of compilation the caller considers up-to-date, and {@code newProfile} 522 | * is used to indicate whether profile information has changed recently. 523 | * 524 | * @param fileName the absolute path to the apk/jar file to examine. 525 | * @param compilerFilter a compiler filter to use for what a caller considers up-to-date. 526 | * @param classLoaderContext a string encoding the class loader context the dex file 527 | * is intended to have at runtime. 528 | * @param newProfile flag that describes whether a profile corresponding 529 | * to the dex file has been recently updated and should be considered 530 | * in the state of the file. 531 | * @param downgrade flag that describes if the purpose of dexopt is to downgrade the 532 | * compiler filter. If set to false, will be evaluated as an upgrade request. 533 | * @return NO_DEXOPT_NEEDED, or DEX2OAT_*. See documentation 534 | * of the particular status code for more information on its 535 | * meaning. Returns a positive status code if the status refers to 536 | * the oat file in the oat location. Returns a negative status 537 | * code if the status refers to the oat file in the odex location. 538 | * @throws java.io.FileNotFoundException if fileName is not readable, 539 | * not a file, or not present. 540 | * @throws java.io.IOException if fileName is not a valid apk/jar file or 541 | * if problems occur while parsing it. 542 | * @throws java.lang.NullPointerException if fileName is null. 543 | * 544 | * @hide 545 | */ 546 | @libcore.api.CorePlatformApi 547 | public static native int getDexOptNeeded(String fileName, 548 | String instructionSet, String compilerFilter, String classLoaderContext, 549 | boolean newProfile, boolean downgrade) 550 | throws FileNotFoundException, IOException; 551 | 552 | /** 553 | * Returns the status of the dex file {@code fileName}. The returned string is 554 | * an opaque, human readable representation of the current status. The output 555 | * is only meant for debugging and is not guaranteed to be stable across 556 | * releases and/or devices. 557 | * 558 | * @hide 559 | */ 560 | public static native String getDexFileStatus(String fileName, String instructionSet) 561 | throws FileNotFoundException; 562 | 563 | /** 564 | * Encapsulates information about the optimizations performed on a dex file. 565 | * 566 | * Note that the info is only meant for debugging and is not guaranteed to be 567 | * stable across releases and/or devices. 568 | * 569 | * @hide 570 | */ 571 | @libcore.api.CorePlatformApi 572 | public static final class OptimizationInfo { 573 | // The optimization status. 574 | private final String status; 575 | // The optimization reason. The reason might be "unknown" if the 576 | // the compiler artifacts were not annotated during optimizations. 577 | private final String reason; 578 | 579 | private OptimizationInfo(String status, String reason) { 580 | this.status = status; 581 | this.reason = reason; 582 | } 583 | 584 | @libcore.api.CorePlatformApi 585 | public String getStatus() { 586 | return status; 587 | } 588 | 589 | @libcore.api.CorePlatformApi 590 | public String getReason() { 591 | return reason; 592 | } 593 | } 594 | 595 | /** 596 | * Retrieves the optimization info for a dex file. 597 | * 598 | * @hide 599 | */ 600 | @libcore.api.CorePlatformApi 601 | public static OptimizationInfo getDexFileOptimizationInfo( 602 | String fileName, String instructionSet) throws FileNotFoundException { 603 | String[] status = getDexFileOptimizationStatus(fileName, instructionSet); 604 | return new OptimizationInfo(status[0], status[1]); 605 | } 606 | 607 | /** 608 | * Returns the optimization status of the dex file {@code fileName}. The returned 609 | * array will have 2 elements which specify: 610 | * - index 0: the level of optimizations 611 | * - index 1: the optimization reason. The reason might be "unknown" if the 612 | * the compiler artifacts were not annotated during optimizations. 613 | * 614 | * The output is only meant for debugging and is not guaranteed to be stable across 615 | * releases and/or devices. 616 | * 617 | * @hide 618 | */ 619 | private static native String[] getDexFileOptimizationStatus( 620 | String fileName, String instructionSet) throws FileNotFoundException; 621 | 622 | /** 623 | * Returns the paths of the optimized files generated for {@code fileName}. 624 | * If no optimized code exists the method returns null. 625 | * @hide 626 | */ 627 | @libcore.api.CorePlatformApi 628 | public static native String[] getDexFileOutputPaths(String fileName, String instructionSet) 629 | throws FileNotFoundException; 630 | 631 | /** 632 | * Returns whether the given filter is a valid filter. 633 | * 634 | * @hide 635 | */ 636 | @libcore.api.CorePlatformApi 637 | public native static boolean isValidCompilerFilter(String filter); 638 | 639 | /** 640 | * Returns whether the given filter is based on profiles. 641 | * 642 | * @hide 643 | */ 644 | @libcore.api.CorePlatformApi 645 | public native static boolean isProfileGuidedCompilerFilter(String filter); 646 | 647 | /** 648 | * Returns the version of the compiler filter that is not based on profiles. 649 | * If the input is not a valid filter, or the filter is already not based on 650 | * profiles, this returns the input. 651 | * 652 | * @hide 653 | */ 654 | public native static String getNonProfileGuidedCompilerFilter(String filter); 655 | 656 | /** 657 | * Returns the version of the compiler filter that is suitable for safe mode. 658 | * If the input is not a valid filter, or the filter is already suitable for 659 | * safe mode, this returns the input. 660 | * 661 | * @hide 662 | */ 663 | @libcore.api.CorePlatformApi 664 | public native static String getSafeModeCompilerFilter(String filter); 665 | 666 | /** 667 | * Returns the static file size of the original dex file. 668 | * The original size of the uncompressed dex file is returned. 669 | * On device the dex file may be compressed or embedded in some other 670 | * file (e.g. oat) in a platform implementation dependent manner. This 671 | * method abstracts away from those details and provides an efficient 672 | * implementation given that the dex file in question has already been 673 | * uncompressed, extracted, and/or loaded by the runtime as appropriate. 674 | *

675 | * In the case of multidex, returns the sum of the original uncompressed 676 | * multidex entry file sizes. 677 | * 678 | * @hide 679 | */ 680 | public long getStaticSizeOfDexFile() { 681 | return getStaticSizeOfDexFile(mCookie); 682 | } 683 | 684 | private static native long getStaticSizeOfDexFile(Object cookie); 685 | } 686 | --------------------------------------------------------------------------------