harmonyos-best-practices-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) hide show
  1. package/README.md +121 -0
  2. package/data/docs/bpta-2in1-window-shape.md +296 -0
  3. package/data/docs/bpta-abckitts-implements-instrumentation.md +1279 -0
  4. package/data/docs/bpta-add-watermark.md +379 -0
  5. package/data/docs/bpta-ads-jump.md +67 -0
  6. package/data/docs/bpta-agent.md +472 -0
  7. package/data/docs/bpta-always-on-market-watch.md +703 -0
  8. package/data/docs/bpta-analysis-of-image-blurring.md +231 -0
  9. package/data/docs/bpta-analyze-memory-problem.md +17 -0
  10. package/data/docs/bpta-animation-frame.md +28 -0
  11. package/data/docs/bpta-antipeep-protection.md +291 -0
  12. package/data/docs/bpta-app-architecture-overview.md +25 -0
  13. package/data/docs/bpta-app-asset-protection-design.md +277 -0
  14. package/data/docs/bpta-app-code-ob.md +180 -0
  15. package/data/docs/bpta-app-concurrency-design.md +1189 -0
  16. package/data/docs/bpta-app-data-security.md +397 -0
  17. package/data/docs/bpta-app-icon-configuration.md +226 -0
  18. package/data/docs/bpta-app-privacy-protection.md +295 -0
  19. package/data/docs/bpta-application-aspect-programming-design.md +675 -0
  20. package/data/docs/bpta-application-cold-start-optimization.md +1397 -0
  21. package/data/docs/bpta-application-continue-progess.md +285 -0
  22. package/data/docs/bpta-application-gesture-share.md +468 -0
  23. package/data/docs/bpta-application-knock-file-share.md +263 -0
  24. package/data/docs/bpta-application-knock-video-share.md +552 -0
  25. package/data/docs/bpta-application-latency-optimization-cases.md +615 -0
  26. package/data/docs/bpta-application-power-analysis.md +15 -0
  27. package/data/docs/bpta-application-power-optimization.md +12 -0
  28. package/data/docs/bpta-application-power-test.md +52 -0
  29. package/data/docs/bpta-application-track-practice.md +595 -0
  30. package/data/docs/bpta-arkts-high-performance.md +464 -0
  31. package/data/docs/bpta-arkts-js-memory-analysis.md +111 -0
  32. package/data/docs/bpta-arkts-language.md +18 -0
  33. package/data/docs/bpta-arkweb-component-security.md +1134 -0
  34. package/data/docs/bpta-arkweb_rendering_framework.md +412 -0
  35. package/data/docs/bpta-aspect-implements-aop.md +505 -0
  36. package/data/docs/bpta-audio-and-video.md +30 -0
  37. package/data/docs/bpta-audio-cast.md +460 -0
  38. package/data/docs/bpta-audio-focus-management.md +862 -0
  39. package/data/docs/bpta-audio-in-ear-monitor.md +803 -0
  40. package/data/docs/bpta-audio-playback-series.md +16 -0
  41. package/data/docs/bpta-audio-record-base-on-audiocapturer.md +188 -0
  42. package/data/docs/bpta-audio-record-base-on-avrecorder-arkts.md +179 -0
  43. package/data/docs/bpta-audio-record-base-on-avrecorder.md +207 -0
  44. package/data/docs/bpta-audio-record-base-on-avscreencapture.md +165 -0
  45. package/data/docs/bpta-audio-record-base-on-ohaudio.md +162 -0
  46. package/data/docs/bpta-audio-record-overview.md +34 -0
  47. package/data/docs/bpta-audio-record.md +16 -0
  48. package/data/docs/bpta-audio-ripple-animation.md +198 -0
  49. package/data/docs/bpta-audio-video-synchronization.md +508 -0
  50. package/data/docs/bpta-audio-video.md +15 -0
  51. package/data/docs/bpta-automated-testing-frameworks.md +481 -0
  52. package/data/docs/bpta-avplayer-basic-control.md +533 -0
  53. package/data/docs/bpta-avplayer-embeded-network-video.md +486 -0
  54. package/data/docs/bpta-avplayer-embeded-short-video.md +512 -0
  55. package/data/docs/bpta-avplayer-long-video.md +907 -0
  56. package/data/docs/bpta-avplayer-short-video.md +158 -0
  57. package/data/docs/bpta-avplayer-video-practices.md +15 -0
  58. package/data/docs/bpta-avscreencapture-for-screen-recording.md +1121 -0
  59. package/data/docs/bpta-back-task-implement.md +317 -0
  60. package/data/docs/bpta-background-blur.md +316 -0
  61. package/data/docs/bpta-background-sensors-baned-analysis.md +93 -0
  62. package/data/docs/bpta-best-practices-long-list.md +891 -0
  63. package/data/docs/bpta-best-practices-overview.md +48 -0
  64. package/data/docs/bpta-bluetooth-low-energy.md +905 -0
  65. package/data/docs/bpta-buffer-mode-transcoding.md +728 -0
  66. package/data/docs/bpta-buffer-power-optimization.md +224 -0
  67. package/data/docs/bpta-camera-shot2see.md +368 -0
  68. package/data/docs/bpta-card-update-and-data-interaction.md +670 -0
  69. package/data/docs/bpta-carousel-graphic-works.md +379 -0
  70. package/data/docs/bpta-cell-phone.md +13 -0
  71. package/data/docs/bpta-click-to-click-response-optimization.md +264 -0
  72. package/data/docs/bpta-click-to-complete-delay-analysis.md +637 -0
  73. package/data/docs/bpta-collaboration-office.md +1178 -0
  74. package/data/docs/bpta-comment-reply-pop-up-window.md +523 -0
  75. package/data/docs/bpta-common-list-flows.md +688 -0
  76. package/data/docs/bpta-common-list-operations.md +828 -0
  77. package/data/docs/bpta-common-network-query.md +784 -0
  78. package/data/docs/bpta-comparative_practice_of_taskpool_and_worker.md +381 -0
  79. package/data/docs/bpta-compatible-scheme.md +11 -0
  80. package/data/docs/bpta-complex-type-pass.md +868 -0
  81. package/data/docs/bpta-component-nesting-optimization.md +421 -0
  82. package/data/docs/bpta-component-reuse-issue-diagnosis-and-analysis.md +637 -0
  83. package/data/docs/bpta-component-reuse.md +1258 -0
  84. package/data/docs/bpta-concurrency-capability.md +23 -0
  85. package/data/docs/bpta-concurrent-optimization.md +369 -0
  86. package/data/docs/bpta-content-creation.md +646 -0
  87. package/data/docs/bpta-continue-cast.md +702 -0
  88. package/data/docs/bpta-continue-data.md +335 -0
  89. package/data/docs/bpta-continue.md +1323 -0
  90. package/data/docs/bpta-control-rendering-range.md +29 -0
  91. package/data/docs/bpta-controlling-background-process-cpu.md +31 -0
  92. package/data/docs/bpta-crash-monitor-practice.md +116 -0
  93. package/data/docs/bpta-cross-domain-solutions-for-web-pages.md +308 -0
  94. package/data/docs/bpta-cross-end-migration.md +13 -0
  95. package/data/docs/bpta-cross-module-reference.md +406 -0
  96. package/data/docs/bpta-cross-platform-compatibility.md +321 -0
  97. package/data/docs/bpta-custom-camera-photo.md +454 -0
  98. package/data/docs/bpta-custom-camera-preview.md +1170 -0
  99. package/data/docs/bpta-custom-camera-video.md +322 -0
  100. package/data/docs/bpta-custom-font-settings.md +354 -0
  101. package/data/docs/bpta-custom-hvigor-plugin.md +159 -0
  102. package/data/docs/bpta-custom-keyboard.md +519 -0
  103. package/data/docs/bpta-customdialog-selection-and-development.md +406 -0
  104. package/data/docs/bpta-dark-mode-adaptation.md +321 -0
  105. package/data/docs/bpta-deal-stride-solution.md +261 -0
  106. package/data/docs/bpta-decrease_pakage_size.md +126 -0
  107. package/data/docs/bpta-delayed-trigger-operation.md +215 -0
  108. package/data/docs/bpta-desktop-shortcuts.md +180 -0
  109. package/data/docs/bpta-detection.md +12 -0
  110. package/data/docs/bpta-developing-high-performance-ui.md +19 -0
  111. package/data/docs/bpta-development-scenarios-for-tabs.md +934 -0
  112. package/data/docs/bpta-dialog-encapsulation.md +201 -0
  113. package/data/docs/bpta-dispose-highly-loaded-component-render.md +352 -0
  114. package/data/docs/bpta-distribute-drag-cast.md +60 -0
  115. package/data/docs/bpta-distributed-pasteboard-cast.md +88 -0
  116. package/data/docs/bpta-distributed-pasteboard.md +314 -0
  117. package/data/docs/bpta-drawing-capability-improve-performance.md +436 -0
  118. package/data/docs/bpta-dynamic-link-library.md +272 -0
  119. package/data/docs/bpta-easygo-parallel.md +402 -0
  120. package/data/docs/bpta-fair-use-animation.md +1693 -0
  121. package/data/docs/bpta-file-transmission-based-on-sfft.md +265 -0
  122. package/data/docs/bpta-file-upload-and-download-performance.md +484 -0
  123. package/data/docs/bpta-foldable-guide.md +205 -0
  124. package/data/docs/bpta-folded-hover.md +202 -0
  125. package/data/docs/bpta-form-kit.md +12 -0
  126. package/data/docs/bpta-frontend-invisible-animation-analysis.md +187 -0
  127. package/data/docs/bpta-full-scenario-collaborative-development.md +13 -0
  128. package/data/docs/bpta-fuzzy-scene-performance-optimization.md +256 -0
  129. package/data/docs/bpta-game-prelaunch-practice.md +175 -0
  130. package/data/docs/bpta-general-comments.md +17 -0
  131. package/data/docs/bpta-gestures-practice.md +619 -0
  132. package/data/docs/bpta-global-state-management-state-store.md +472 -0
  133. package/data/docs/bpta-gpu-acceleration-practices.md +11 -0
  134. package/data/docs/bpta-graphic-drawing-practices.md +13 -0
  135. package/data/docs/bpta-grid-based-on-scrollcomponents.md +1112 -0
  136. package/data/docs/bpta-grid-drag-swap.md +725 -0
  137. package/data/docs/bpta-hadss_dialoghub.md +786 -0
  138. package/data/docs/bpta-harmony-application-security.md +1253 -0
  139. package/data/docs/bpta-hdrtosdr.md +439 -0
  140. package/data/docs/bpta-hdrvivid.md +700 -0
  141. package/data/docs/bpta-high-cpu-load-analysis.md +113 -0
  142. package/data/docs/bpta-high-performance-json-parsing.md +263 -0
  143. package/data/docs/bpta-high-performance-protobuf-parsing.md +259 -0
  144. package/data/docs/bpta-hmos-live-stream-audio-call.md +140 -0
  145. package/data/docs/bpta-hmos-live-stream-solution.md +495 -0
  146. package/data/docs/bpta-hmrouter.md +659 -0
  147. package/data/docs/bpta-hopping.md +60 -0
  148. package/data/docs/bpta-hwc-self-rendering-layer-analysis.md +77 -0
  149. package/data/docs/bpta-image-processing-practices.md +13 -0
  150. package/data/docs/bpta-image-to-video-synthesis.md +459 -0
  151. package/data/docs/bpta-image-white-lump-solution.md +282 -0
  152. package/data/docs/bpta-image_get_and_save.md +120 -0
  153. package/data/docs/bpta-implement-timeline-based-on-canvas.md +493 -0
  154. package/data/docs/bpta-implementing-image-filters.md +406 -0
  155. package/data/docs/bpta-implementing-image-resizable.md +270 -0
  156. package/data/docs/bpta-improve-layout-performance.md +547 -0
  157. package/data/docs/bpta-improve-running-efficiency.md +187 -0
  158. package/data/docs/bpta-improve_grid_performance.md +268 -0
  159. package/data/docs/bpta-input-method-framework.md +12 -0
  160. package/data/docs/bpta-intent-recommend-practice.md +313 -0
  161. package/data/docs/bpta-js-leak-watcher.md +153 -0
  162. package/data/docs/bpta-kernel-memory-analysis.md +38 -0
  163. package/data/docs/bpta-keyboard-layout-adapt.md +725 -0
  164. package/data/docs/bpta-landscape-and-portrait-development.md +947 -0
  165. package/data/docs/bpta-layered-architecture-design.md +82 -0
  166. package/data/docs/bpta-lazyforeach-optimization.md +217 -0
  167. package/data/docs/bpta-link-between-apps-overview.md +99 -0
  168. package/data/docs/bpta-list-based-on-scrollcomponents.md +1643 -0
  169. package/data/docs/bpta-lite-wearable-guide.md +1899 -0
  170. package/data/docs/bpta-live-form-development-practice.md +544 -0
  171. package/data/docs/bpta-live-streaming-optimization.md +397 -0
  172. package/data/docs/bpta-local-file-and-data-multithreaded-io.md +367 -0
  173. package/data/docs/bpta-local-file.md +11 -0
  174. package/data/docs/bpta-lock-screen-immersive-live-window.md +473 -0
  175. package/data/docs/bpta-long-snapshot-practice.md +1046 -0
  176. package/data/docs/bpta-low-power-consumption-of-background-tasks.md +14 -0
  177. package/data/docs/bpta-low-power-consumption-of-foreground-tasks.md +14 -0
  178. package/data/docs/bpta-low-power-design-in-dark-mode.md +418 -0
  179. package/data/docs/bpta-ltpo-description.md +323 -0
  180. package/data/docs/bpta-maleoon-gpu-best-practices.md +1297 -0
  181. package/data/docs/bpta-malloc-dispatch-table.md +144 -0
  182. package/data/docs/bpta-managing-audio-input-devices.md +350 -0
  183. package/data/docs/bpta-managing-audio-output-devices.md +399 -0
  184. package/data/docs/bpta-mate-book-fold.md +229 -0
  185. package/data/docs/bpta-matetv-guide.md +223 -0
  186. package/data/docs/bpta-matext-guide.md +269 -0
  187. package/data/docs/bpta-memory-basic-knowledge.md +71 -0
  188. package/data/docs/bpta-memory-optimization.md +545 -0
  189. package/data/docs/bpta-modular-design.md +282 -0
  190. package/data/docs/bpta-multi-device-adaptive-layout.md +775 -0
  191. package/data/docs/bpta-multi-device-adaptive.md +11 -0
  192. package/data/docs/bpta-multi-device-camera.md +584 -0
  193. package/data/docs/bpta-multi-device-collaboration.md +19 -0
  194. package/data/docs/bpta-multi-device-component-layout.md +190 -0
  195. package/data/docs/bpta-multi-device-design-principles.md +26 -0
  196. package/data/docs/bpta-multi-device-function.md +99 -0
  197. package/data/docs/bpta-multi-device-hardware.md +12 -0
  198. package/data/docs/bpta-multi-device-ide.md +124 -0
  199. package/data/docs/bpta-multi-device-interaction.md +11 -0
  200. package/data/docs/bpta-multi-device-layout-overview.md +47 -0
  201. package/data/docs/bpta-multi-device-overview.md +340 -0
  202. package/data/docs/bpta-multi-device-page-layout.md +699 -0
  203. package/data/docs/bpta-multi-device-page.md +19 -0
  204. package/data/docs/bpta-multi-device-resource.md +122 -0
  205. package/data/docs/bpta-multi-device-responsive-layout.md +1274 -0
  206. package/data/docs/bpta-multi-device-responsive.md +14 -0
  207. package/data/docs/bpta-multi-device-screen-diff.md +197 -0
  208. package/data/docs/bpta-multi-device-screen-layout.md +834 -0
  209. package/data/docs/bpta-multi-device-start.md +376 -0
  210. package/data/docs/bpta-multi-device-ui-development.md +27 -0
  211. package/data/docs/bpta-multi-device-window-direction.md +1322 -0
  212. package/data/docs/bpta-multi-device-window-immersive.md +364 -0
  213. package/data/docs/bpta-multi-device-window-mode.md +1293 -0
  214. package/data/docs/bpta-multi-device-window.md +13 -0
  215. package/data/docs/bpta-multi-device.md +13 -0
  216. package/data/docs/bpta-multi-interaction.md +368 -0
  217. package/data/docs/bpta-multi-mobile-payment.md +282 -0
  218. package/data/docs/bpta-multi-music-app-overview.md +365 -0
  219. package/data/docs/bpta-multi-settings-application-page.md +163 -0
  220. package/data/docs/bpta-multi-tab-practice.md +750 -0
  221. package/data/docs/bpta-multi-target.md +490 -0
  222. package/data/docs/bpta-multi-window-practice.md +795 -0
  223. package/data/docs/bpta-multi_game.md +472 -0
  224. package/data/docs/bpta-music-card.md +1916 -0
  225. package/data/docs/bpta-music-playback-scenarios.md +120 -0
  226. package/data/docs/bpta-native-memory-analysis.md +101 -0
  227. package/data/docs/bpta-native-sub-main-comm.md +323 -0
  228. package/data/docs/bpta-navigation-scenarios.md +69 -0
  229. package/data/docs/bpta-network-ca-security.md +241 -0
  230. package/data/docs/bpta-network-reconnection.md +327 -0
  231. package/data/docs/bpta-network-resources.md +24 -0
  232. package/data/docs/bpta-news-reading.md +12 -0
  233. package/data/docs/bpta-news_homepage.md +449 -0
  234. package/data/docs/bpta-object-serialization-performance.md +12 -0
  235. package/data/docs/bpta-one-shot-to-the-end.md +932 -0
  236. package/data/docs/bpta-online-video-playback-lags-practice.md +298 -0
  237. package/data/docs/bpta-optimization-overview.md +227 -0
  238. package/data/docs/bpta-optimization-tool-practice.md +20 -0
  239. package/data/docs/bpta-package-structure.md +13 -0
  240. package/data/docs/bpta-pad-guide.md +268 -0
  241. package/data/docs/bpta-page-brightness-settings.md +256 -0
  242. package/data/docs/bpta-page-transition.md +583 -0
  243. package/data/docs/bpta-pc-guide.md +438 -0
  244. package/data/docs/bpta-pc.md +12 -0
  245. package/data/docs/bpta-perceived-smoothness.md +49 -0
  246. package/data/docs/bpta-performance-detection.md +160 -0
  247. package/data/docs/bpta-performance-guide-reading.md +50 -0
  248. package/data/docs/bpta-performance-mainthread-consumption-detection.md +11 -0
  249. package/data/docs/bpta-performance-optimization.md +23 -0
  250. package/data/docs/bpta-performance-runtime-detection.md +13 -0
  251. package/data/docs/bpta-performance-sliding-frame-drop-detection.md +19 -0
  252. package/data/docs/bpta-performance-startup-time-detection.md +13 -0
  253. package/data/docs/bpta-permission-application.md +318 -0
  254. package/data/docs/bpta-permission-timeout-analysis.md +51 -0
  255. package/data/docs/bpta-photo.md +15 -0
  256. package/data/docs/bpta-picture-preview.md +464 -0
  257. package/data/docs/bpta-picture.md +12 -0
  258. package/data/docs/bpta-playing-formatted-audio-based-avplayer-arkts.md +481 -0
  259. package/data/docs/bpta-playing-formatted-audio-based-avplayer-cpp.md +593 -0
  260. package/data/docs/bpta-playing-pcm-audio-based-audiorenderer.md +959 -0
  261. package/data/docs/bpta-playing-pcm-audio-based-ohaudio.md +599 -0
  262. package/data/docs/bpta-playing-short-audio-based-soundpool.md +182 -0
  263. package/data/docs/bpta-positioning.md +364 -0
  264. package/data/docs/bpta-power-basic-quality-test.md +35 -0
  265. package/data/docs/bpta-power-consumption-analysis.md +12 -0
  266. package/data/docs/bpta-power-consumption-develop-analysis.md +12 -0
  267. package/data/docs/bpta-power-consumption-experience.md +119 -0
  268. package/data/docs/bpta-power-consumption-runtime-analysis.md +15 -0
  269. package/data/docs/bpta-power_overview.md +26 -0
  270. package/data/docs/bpta-pptimized-component-drawing.md +27 -0
  271. package/data/docs/bpta-pre-connect.md +133 -0
  272. package/data/docs/bpta-preloading-resources.md +21 -0
  273. package/data/docs/bpta-program-framework.md +15 -0
  274. package/data/docs/bpta-properly-use-foreground-resources.md +22 -0
  275. package/data/docs/bpta-purax-guide.md +215 -0
  276. package/data/docs/bpta-quality-overview.md +79 -0
  277. package/data/docs/bpta-reader-page-flip.md +890 -0
  278. package/data/docs/bpta-reasonable-audio-playback-use.md +42 -0
  279. package/data/docs/bpta-reasonable-audio-use.md +163 -0
  280. package/data/docs/bpta-reasonable-bluetooth-use.md +52 -0
  281. package/data/docs/bpta-reasonable-gps-use.md +59 -0
  282. package/data/docs/bpta-reasonable-network-use.md +105 -0
  283. package/data/docs/bpta-reasonable-position-navigation-use.md +47 -0
  284. package/data/docs/bpta-reasonable-request-use.md +77 -0
  285. package/data/docs/bpta-reasonable-sensor-use.md +53 -0
  286. package/data/docs/bpta-reasonable-system-use.md +67 -0
  287. package/data/docs/bpta-recommended-use-of-device-id.md +79 -0
  288. package/data/docs/bpta-reduce-layout-nodes.md +30 -0
  289. package/data/docs/bpta-reduce-time-consuming.md +36 -0
  290. package/data/docs/bpta-redundancy-refresh-guide.md +409 -0
  291. package/data/docs/bpta-render-web-using-same-layer-render.md +601 -0
  292. package/data/docs/bpta-resource-and-storage-optimization.md +14 -0
  293. package/data/docs/bpta-retrieve-process-memory-info.md +49 -0
  294. package/data/docs/bpta-rich-text-display.md +475 -0
  295. package/data/docs/bpta-rich-text-editor.md +426 -0
  296. package/data/docs/bpta-risk-control-engine.md +146 -0
  297. package/data/docs/bpta-scenario-performance-optimization.md +17 -0
  298. package/data/docs/bpta-scenario-power-optimization.md +12 -0
  299. package/data/docs/bpta-scenario-stability-address-sanitizer.md +210 -0
  300. package/data/docs/bpta-scenario-stability-app-freeze.md +615 -0
  301. package/data/docs/bpta-scenario-stability-cppcrash.md +516 -0
  302. package/data/docs/bpta-scenario-stability-exception-exit.md +12 -0
  303. package/data/docs/bpta-scenario-stability-jscrash.md +922 -0
  304. package/data/docs/bpta-scenario-stability-leak.md +276 -0
  305. package/data/docs/bpta-scenario-stability.md +14 -0
  306. package/data/docs/bpta-screen-flicker-solution.md +480 -0
  307. package/data/docs/bpta-shared-bicycle.md +509 -0
  308. package/data/docs/bpta-short-video-base-adaptivevideo.md +403 -0
  309. package/data/docs/bpta-smart-reach.md +306 -0
  310. package/data/docs/bpta-smartwatch.md +755 -0
  311. package/data/docs/bpta-smartwatchnavigation.md +384 -0
  312. package/data/docs/bpta-smooth-application-design.md +225 -0
  313. package/data/docs/bpta-smooth-switching.md +294 -0
  314. package/data/docs/bpta-social-communications.md +11 -0
  315. package/data/docs/bpta-social-share.md +637 -0
  316. package/data/docs/bpta-solutions-to-special-issues.md +12 -0
  317. package/data/docs/bpta-sound-quality-switching.md +422 -0
  318. package/data/docs/bpta-spatiality-immersive.md +531 -0
  319. package/data/docs/bpta-special-text-recognition.md +137 -0
  320. package/data/docs/bpta-stability-address-illegal-way.md +190 -0
  321. package/data/docs/bpta-stability-address-sanitizer-catagory.md +212 -0
  322. package/data/docs/bpta-stability-address-sanitizer-faq.md +32 -0
  323. package/data/docs/bpta-stability-address-sanitizer-opt.md +170 -0
  324. package/data/docs/bpta-stability-address-sanitizer-overview.md +23 -0
  325. package/data/docs/bpta-stability-address-sanitizer-principle.md +179 -0
  326. package/data/docs/bpta-stability-analysis.md +17 -0
  327. package/data/docs/bpta-stability-app-analyzer.md +11 -0
  328. package/data/docs/bpta-stability-app-crash-cpp-way.md +200 -0
  329. package/data/docs/bpta-stability-app-crash-js-way.md +148 -0
  330. package/data/docs/bpta-stability-app-crash.md +13 -0
  331. package/data/docs/bpta-stability-app-freeze-ark-runtime.md +339 -0
  332. package/data/docs/bpta-stability-app-freeze-opt.md +80 -0
  333. package/data/docs/bpta-stability-app-freeze-way.md +410 -0
  334. package/data/docs/bpta-stability-app-freeze.md +12 -0
  335. package/data/docs/bpta-stability-app-killed-way.md +49 -0
  336. package/data/docs/bpta-stability-ark-detection.md +12 -0
  337. package/data/docs/bpta-stability-ark-exception-detection.md +38 -0
  338. package/data/docs/bpta-stability-ark-runtime-detection.md +134 -0
  339. package/data/docs/bpta-stability-asan-detection.md +450 -0
  340. package/data/docs/bpta-stability-coding-standard-api.md +2054 -0
  341. package/data/docs/bpta-stability-coding-standard-cpp.md +91 -0
  342. package/data/docs/bpta-stability-coding-standard-libuv.md +772 -0
  343. package/data/docs/bpta-stability-coding-standard-ndk-arkts.md +189 -0
  344. package/data/docs/bpta-stability-coding-standard-node.md +478 -0
  345. package/data/docs/bpta-stability-coding-standard.md +16 -0
  346. package/data/docs/bpta-stability-cpp-crash-opt.md +346 -0
  347. package/data/docs/bpta-stability-detection.md +14 -0
  348. package/data/docs/bpta-stability-deveco-testing.md +73 -0
  349. package/data/docs/bpta-stability-develop-detection.md +17 -0
  350. package/data/docs/bpta-stability-exception-exit-opt.md +12 -0
  351. package/data/docs/bpta-stability-fault-log.md +14 -0
  352. package/data/docs/bpta-stability-fault-type.md +31 -0
  353. package/data/docs/bpta-stability-file-handle-detection.md +96 -0
  354. package/data/docs/bpta-stability-gwpasan-detection.md +588 -0
  355. package/data/docs/bpta-stability-hwasan-detection.md +360 -0
  356. package/data/docs/bpta-stability-ide-static-detection.md +343 -0
  357. package/data/docs/bpta-stability-js-crash-opt.md +21 -0
  358. package/data/docs/bpta-stability-js-memleak-detection.md +214 -0
  359. package/data/docs/bpta-stability-leak-detection.md +15 -0
  360. package/data/docs/bpta-stability-leak-opt.md +251 -0
  361. package/data/docs/bpta-stability-leak-way.md +459 -0
  362. package/data/docs/bpta-stability-log-specs.md +31 -0
  363. package/data/docs/bpta-stability-log-standard-hilog.md +191 -0
  364. package/data/docs/bpta-stability-log-standard.md +11 -0
  365. package/data/docs/bpta-stability-memleak-detection-overview.md +109 -0
  366. package/data/docs/bpta-stability-native-memleak-detection.md +204 -0
  367. package/data/docs/bpta-stability-operate-apm.md +113 -0
  368. package/data/docs/bpta-stability-operate-app-event.md +320 -0
  369. package/data/docs/bpta-stability-operate-event.md +11 -0
  370. package/data/docs/bpta-stability-operate.md +15 -0
  371. package/data/docs/bpta-stability-opt.md +18 -0
  372. package/data/docs/bpta-stability-overview.md +17 -0
  373. package/data/docs/bpta-stability-ram-detection.md +17 -0
  374. package/data/docs/bpta-stability-runtime-address-sanitizer-detection.md +21 -0
  375. package/data/docs/bpta-stability-runtime-appkilled-detection.md +44 -0
  376. package/data/docs/bpta-stability-runtime-crash-detection.md +14 -0
  377. package/data/docs/bpta-stability-runtime-detection.md +14 -0
  378. package/data/docs/bpta-stability-runtime-exception-exit-detection.md +12 -0
  379. package/data/docs/bpta-stability-runtime-freeze-detection.md +21 -0
  380. package/data/docs/bpta-stability-runtime-leak-detection.md +31 -0
  381. package/data/docs/bpta-stability-testing.md +11 -0
  382. package/data/docs/bpta-stability-thread-detection.md +11 -0
  383. package/data/docs/bpta-stability-thread-leak-detection.md +35 -0
  384. package/data/docs/bpta-stability-tsan-detection.md +477 -0
  385. package/data/docs/bpta-stability-ubsan-detection.md +350 -0
  386. package/data/docs/bpta-startup-response-optimization.md +12 -0
  387. package/data/docs/bpta-state-refresh.md +48 -0
  388. package/data/docs/bpta-static-scenarios.md +63 -0
  389. package/data/docs/bpta-status-management.md +872 -0
  390. package/data/docs/bpta-surface-encoder.md +427 -0
  391. package/data/docs/bpta-swiper_high_performance_development_guide.md +357 -0
  392. package/data/docs/bpta-tablet-pc.md +11 -0
  393. package/data/docs/bpta-taskpool_usage_specifications_and_faqs.md +625 -0
  394. package/data/docs/bpta-text-expand-collapse.md +274 -0
  395. package/data/docs/bpta-texture-compression-improve-performance.md +336 -0
  396. package/data/docs/bpta-thread-priority-setting.md +233 -0
  397. package/data/docs/bpta-threads-serialization-timeout-analysis.md +169 -0
  398. package/data/docs/bpta-time-optimization-of-the-main-thread.md +1239 -0
  399. package/data/docs/bpta-travel-navigation.md +11 -0
  400. package/data/docs/bpta-tv.md +11 -0
  401. package/data/docs/bpta-ui-component-encapsulation.md +585 -0
  402. package/data/docs/bpta-ui-component-performance-optimization.md +597 -0
  403. package/data/docs/bpta-ui-dynamic-operations.md +618 -0
  404. package/data/docs/bpta-ui-skip-analysis.md +191 -0
  405. package/data/docs/bpta-unified-drag-and-drop.md +1189 -0
  406. package/data/docs/bpta-use-of-background-hardware-resources.md +16 -0
  407. package/data/docs/bpta-use-of-background-software-resources.md +14 -0
  408. package/data/docs/bpta-use-of-background-tasks.md +23 -0
  409. package/data/docs/bpta-utilize-hwc-efficiently.md +461 -0
  410. package/data/docs/bpta-vdeocast.md +558 -0
  411. package/data/docs/bpta-video-adaptation-based-web.md +462 -0
  412. package/data/docs/bpta-video-barrage.md +68 -0
  413. package/data/docs/bpta-video-codec.md +42 -0
  414. package/data/docs/bpta-video-component-long-video.md +659 -0
  415. package/data/docs/bpta-video-component-short-video.md +337 -0
  416. package/data/docs/bpta-video-layer.md +32 -0
  417. package/data/docs/bpta-video-practices.md +12 -0
  418. package/data/docs/bpta-video-render.md +1225 -0
  419. package/data/docs/bpta-video-rom.md +37 -0
  420. package/data/docs/bpta-video-thumbnail.md +179 -0
  421. package/data/docs/bpta-video-wifi.md +40 -0
  422. package/data/docs/bpta-vsync-power-optimization.md +116 -0
  423. package/data/docs/bpta-waterflow-based-on-scrollcomponents.md +989 -0
  424. package/data/docs/bpta-waterflow-operations.md +991 -0
  425. package/data/docs/bpta-waterflow-performance-optimization.md +191 -0
  426. package/data/docs/bpta-wavewheel-for-image-editor.md +421 -0
  427. package/data/docs/bpta-wear.md +12 -0
  428. package/data/docs/bpta-web-adaptation.md +451 -0
  429. package/data/docs/bpta-web-app-jump-and-pull-up.md +310 -0
  430. package/data/docs/bpta-web-click-response-delay-analysis.md +164 -0
  431. package/data/docs/bpta-web-completion-delay-analysis.md +209 -0
  432. package/data/docs/bpta-web-develop-optimization.md +2596 -0
  433. package/data/docs/bpta-web-development.md +15 -0
  434. package/data/docs/bpta-web-frame-rate-performance-analysis.md +252 -0
  435. package/data/docs/bpta-web-interceptor.md +724 -0
  436. package/data/docs/bpta-web-performance-optimization.md +11 -0
  437. package/data/docs/bpta-window-and-screen-management.md +12 -0
  438. package/data/docs/bpta-zhenlv.md +559 -0
  439. package/data/docs/changelog.md +1410 -0
  440. package/data/docs/low-power-consumption-suggestions.md +246 -0
  441. package/data/docs/multi-business-office.md +275 -0
  442. package/data/docs/multi-communication-app.md +240 -0
  443. package/data/docs/multi-community-app.md +257 -0
  444. package/data/docs/multi-convenient-life.md +501 -0
  445. package/data/docs/multi-financial-app.md +288 -0
  446. package/data/docs/multi-news-read.md +286 -0
  447. package/data/docs/multi-picture-app.md +219 -0
  448. package/data/docs/multi-shopping-price-comparison.md +254 -0
  449. package/data/docs/multi-short-video-app.md +315 -0
  450. package/data/docs/multi-ticket-class.md +458 -0
  451. package/data/docs/multi-travel-accommodation.md +361 -0
  452. package/data/docs/multi-travel-navigation.md +449 -0
  453. package/data/docs/multi-video-app.md +492 -0
  454. package/data/index.md +2886 -0
  455. package/dist/data.js +180 -0
  456. package/dist/index.js +203 -0
  457. package/dist/search.js +102 -0
  458. package/package.json +57 -0
  459. package/scripts/trim-code-extra.mjs +78 -0
  460. package/scripts/trim-code.mjs +106 -0
@@ -0,0 +1,1279 @@
1
+ # 基于AbcKitTS实现字节码插桩
2
+
3
+ > 来源: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-abckitts-implements-instrumentation
4
+ > 文档标识(fileName): bpta-abckitts-implements-instrumentation
5
+ > 目录(catalogName): best-practices
6
+ > 语言: cn
7
+ > 更新时间: 2026-06-23 03:35:15
8
+ > 导航地址: /hmos/hmos-dp1
9
+
10
+ ---
11
+ #### 概述
12
+
13
+ AbcKitTS是一款专为方舟字节码设计的TypeScript字节码分析与修改工具库。它提供了简洁而强大的字节码操作API,让开发者能够精确定位目标方法、拦截API调用、注入回调逻辑,并支持灵活的字节码指令创建与修改,从而实现高效的切面编程。本文将从实际业务场景出发,深入剖析AbcKitTS在切面编程中的高频应用模式,分享最佳实践与实现技巧。
14
+
15
+ 同时,针对轻量化的业务需求,可以参考基于装饰器配置的[基于Aspect插件库实现切面编程](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-aspect-implements-aop)——它完全封装了底层的字节码技术,让开发者以声明式的方式快速实现切面功能,真正做到"零侵入"式开发。
16
+
17
+ #### 实现原理
18
+
19
+ 在深入实践之前,建议先通过官方文档了解[方舟字节码](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-bytecode)的基本原理,并掌握[Disassembler反汇编工具](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/tool-disassembler)的基础技能,这将有助于更好地理解后续内容。
20
+
21
+ ## 底层架构
22
+
23
+ AbcKitTS是基于C++版[libabckit](https://gitcode.com/openharmony/arkcompiler_runtime_core/tree/master/libabckit)方舟字节码工具库的TypeScript封装,旨在提升开发者的字节码插桩效率。通过提供易用的API接口,它将底层复杂的字节码操作抽象为简洁的开发体验。
24
+
25
+ ## 核心设计:扁平化的元数据模型
26
+
27
+ AbcKitTS通过AbcManager统一管理字节码文件,并提供链式查询API供开发者快速定位目标方法。其元数据模型在设计上独具匠心:底层虽然遵循源程序的"树形结构",但对外提供了扁平化的查询视图,极大地简化了数据检索过程。
28
+
29
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/20/v3/toEd9y2PTkKT-862p_3FXw/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=67CE3477A0B3CD539AC1060209E14562D34DAED3A546EEDC3D390F81BD5530E8)
30
+
31
+ AbcManager是字节码操作统一管理器,其核心功能包括加载、查询和修改字节码。
32
+
33
+ 以namespace a { namespace b { ... } }的嵌套结构为例,在AbcModule的AbcNamespace[]列表中会保存为两条独立的命名空间数据,开发者无需进行嵌套遍历即可直接访问。
34
+
35
+ 元数据结构详解:
36
+
37
+ | 节点类型 | 对应关系 | 设计特点 |
38
+ | --- | --- | --- |
39
+ | AbcModule | ets/ts源文件 | 包含文件内所有命名空间、类、顶层函数(包括匿名回调函数); 持有特殊的func_main_0入口函数,记录文件顶层的语句执行及声明。 |
40
+ | AbcNamespace | 命名空间 | 采用扁平化设计,仅持有该命名空间内的顶层函数,其内部的类统一由AbcModule持有。 |
41
+ | AbcClass | 类定义 | 持有类方法,但不包含方法内部定义的匿名回调函数,后者被保存在AbcModule中。 |
42
+ | AbcFunction | 函数/方法 | 可遍历Block块,也可直接遍历指令。底层解析时,实际是从外层Block到内层Instruction的顺序逐层解析。 |
43
+ | Block | 代码块 | 函数体由多个Block构成(至少3个:startBlock、endBlock及startBlock的后继块); 支持代码分支语句(如if-else、try-catch)构建,常用于入参校验、返回值校验、异常捕捉等代码结构改造场景。 |
44
+ | Instruction | 指令序列 | 字节码的基本执行单元,绝大多数插桩功能通过创建或修改指令完成。 |
45
+
46
+ ## 指令操作:IsaKit的设计要点
47
+
48
+ IsaKit是AbcKitTS提供的核心指令操作工具,用于操作方法的Block及Instruction。
49
+
50
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/03/v3/r_i8grcmQduoR-terRj5SA/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=03BC90CB5A3A5BF797EC7D3323DBCCA4394EC7E08D5B2DDA8A60D29EE139558A)
51
+
52
+ 使用时需要特别注意:
53
+
54
+ - 作用域限定:IsaKit必须通过AbcFunction实例获取,不同方法拥有独立的IsaKit实例。
55
+ - 避免混淆:在回调函数分析等场景中,切勿跨方法混用IsaKit,否则可能导致指令操作错乱。
56
+
57
+ 本文主要内容如下:
58
+
59
+ - [开发流程](#section1179862361313):介绍所有场景通用的开发流程。
60
+ - [场景示例](#section21172491410):通过实际开发中的场景,介绍基于AbcKitTS的基本使用方法。
61
+ - 生命周期函数打点
62
+ - 函数耗时统计
63
+ - 隐私API监控
64
+ - 方法调用点替换
65
+ - 关键属性修改
66
+ - 事件监听埋点
67
+ - 方法入参校验
68
+ - [示例代码](#section129251397148):本文引用的工程代码。
69
+
70
+ #### 开发流程
71
+
72
+ 开发者要使用AbckitTS对HarmonyOS工程进行插桩,需要完成两个步骤:**编写插桩代码**和**注册插件**。其中,插桩代码的编写会根据具体业务逻辑而有所不同,本文将在[场景示例](#section21172491410)中根据不同业务场景详细介绍实现方法。
73
+
74
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c/v3/zs4RMpibQvCAwwEHoAqeTA/zh-cn_image_0000002568136792.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=D7AB45D0707654FBAA77A239F183549E81AA30063BCA710C0381C696197D1F70 "点击放大")
75
+
76
+ ## 编写插桩代码
77
+
78
+ 编写TypeScript插桩代码时,可以在项目根目录下新建TS子工程,用于开发插桩逻辑代码。
79
+
80
+ ```
81
+ .
82
+ ├──entry/src/main/ets // entry module
83
+ ├──abckitTask // abckitTask directory
84
+ │ └──src
85
+ │ │ ├──task
86
+ │ │ │ └──CallReplaceTask.ts // instrumentation code
87
+ │ │ └──index.ts // instrumentation Entry Point
88
+ │ └──package.json // Node.js configuration
89
+ │ └──tsconfig.json // TypeScript project connfiguration
90
+ ├──hvigorfile.ts // registering a Plug-in
91
+ ├──...
92
+ └──README.md
93
+ ```
94
+
95
+ 1. 初始化插桩任务工程,配置package.json。
96
+
97
+ ```
98
+ {
99
+ "name": "abckit-ts-task",
100
+ "version": "1.0.0",
101
+ "description": "",
102
+ "main": "index.js",
103
+ "scripts": {
104
+ "test": "echo \"Error: no test specified\" && exit 1"
105
+ },
106
+ "author": "",
107
+ "license": "ISC",
108
+ "devDependencies": {
109
+ "@types/node": "^25.5.0",
110
+ "typescript": "^5.9.3"
111
+ },
112
+ "dependencies": {
113
+ "@hadss/abckit-ts": "1.0.0-rc.0"
114
+ }
115
+ }
116
+ ```
117
+
118
+ 配置tsconfig.json。
119
+
120
+ ```
121
+ {
122
+ "compilerOptions": {
123
+ "target": "ES6",
124
+ "moduleResolution": "node",
125
+ "module": "commonjs",
126
+ "esModuleInterop": true,
127
+ "allowSyntheticDefaultImports": true,
128
+ "outDir": "./dist",
129
+ "rootDir": "./src",
130
+ "strict": true
131
+ },
132
+ "include": [
133
+ "src/**/*"
134
+ ],
135
+ "exclude": [
136
+ "node_modules"
137
+ ]
138
+ }
139
+ ```
140
+
141
+ 安装依赖:
142
+
143
+ ```
144
+ npm install
145
+ ```
146
+ 2. 编写插桩任务。
147
+ 3. 编写入口脚本。
148
+
149
+ 这里推荐使用worker_threads子线程方式执行插桩任务,可以避免DevEco Studio、Hvigor、Native跨环境调用可能产生的内存访问异常的问题。
150
+
151
+ ```
152
+ import { CallReplaceTask } from './task/CallReplaceTask';
153
+ import { DurationTask } from './task/DurationTask';
154
+ import { EventCbTask } from './task/EventCbTask';
155
+ import { KeyAttributeModifyTask } from './task/KeyAttributeModifyTask';
156
+ import { LifeCycleTask } from './task/LifeCycleTask';
157
+ import { MethodParameterValidateTask } from './task/MethodParameterValidateTask';
158
+ import { PrivacyApiScanTask } from './task/PrivacyApiScanTask';
159
+ import { AbcManager } from '@hadss/abckit-ts';
160
+
161
+ const fs = require('fs');
162
+ const abcPath = process.argv[2]
163
+ const outPath = `${abcPath}.bak`
164
+
165
+ export function runTest(abcPath: string, outPath: string): void {
166
+ const abcManger = new AbcManager(abcPath);
167
+ new DurationTask(abcManger).run();
168
+ new EventCbTask(abcManger).run();
169
+ new CallReplaceTask(abcManger).run();
170
+ new KeyAttributeModifyTask(abcManger).run();
171
+ new LifeCycleTask(abcManger).run();
172
+ new MethodParameterValidateTask(abcManger).run();
173
+ new PrivacyApiScanTask(abcManger).run();
174
+ abcManger.writeAbc(outPath);
175
+ fs.renameSync(outPath, abcPath);
176
+ }
177
+
178
+ try {
179
+ runTest(abcPath, outPath);
180
+
181
+ process.exit(0)
182
+ } catch (err) {
183
+ console.error('error: ', err instanceof Error ? err.message : err)
184
+ process.exit(1)
185
+ }
186
+ ```
187
+ 4. 编译构建abckitTask工程。
188
+
189
+ ```
190
+ cd abckitTask && npx tsc
191
+ ```
192
+
193
+ 至此,Hvigor Plugin准备好了插桩任务调用入口dist/index.js。
194
+
195
+ ## 注册插件
196
+
197
+ AbcKitTS插桩接口基于Hvigor插件开发,具体流程可参考[《开发Hvigor插件》](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-hvigor-plugin)文档。
198
+
199
+ 本最佳实践基于hvigorfile脚本开发,在hvigorfile.ts中定义aspectPlugin()函数。
200
+
201
+ ```
202
+ import { hvigor, HvigorNode, HvigorPlugin } from '@ohos/hvigor';
203
+ import { appTasks, OhosPluginId, OhosHapContext, OhosHspContext, OhosHarContext } from '@ohos/hvigor-ohos-plugin';
204
+
205
+ const { spawnSync } = require('child_process');
206
+
207
+ type OhosContext = OhosHapContext | OhosHspContext | OhosHarContext;
208
+
209
+ export default {
210
+ system: appTasks,
211
+ plugins: [
212
+ aspectPlugin(),
213
+ ],
214
+ };
215
+
216
+ function aspectPlugin(): HvigorPlugin {
217
+ return {
218
+ pluginId: 'aspectPlugin',
219
+ apply(node: HvigorNode) : void {
220
+ hvigor.nodesEvaluated(async () => {
221
+ const hotReload = hvigor.getParameter().getExtParam('hotReload');
222
+ if (hotReload) {
223
+ return;
224
+ }
225
+ node.subNodes(subNode => {
226
+ const context = (
227
+ subNode.getContext(OhosPluginId.OHOS_HAP_PLUGIN) ??
228
+ subNode.getContext(OhosPluginId.OHOS_HSP_PLUGIN) ??
229
+ subNode.getContext(OhosPluginId.OHOS_HAR_PLUGIN)
230
+ ) as OhosContext | undefined;
231
+ if (!context) {
232
+ return;
233
+ }
234
+ context.transformAbc(async (abcPath: string, config: any) => {
235
+ console.log("[Final] Abckit Task Start! ");
236
+ const child = spawnSync('node', ['./abckitTask/dist/index.js', abcPath]);
237
+ if (child.status !== 3221225477 && child.status !== 0) {
238
+ throw new Error(child.status);
239
+ }
240
+ console.log("[Final] Abckit Task Completed! ABC File generated.");
241
+ });
242
+ });
243
+ });
244
+ },
245
+ };
246
+ }
247
+ ```
248
+
249
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/72/v3/pFiwnMB9ReeLgXTRzP2NTQ/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=D87153B2A9F5B8C2F04E0A8A37CE9DFC51BDBDE307938310005F44FD153E5583)
250
+
251
+ 1. AbcKitTS不支持HotReload模式。
252
+
253
+ 2. OHOS_HAR_PLUGIN、OHOS_HSP_PLUGIN和OHOS_HAP_PLUGIN分别对应har、hsp和hap三种包类型。
254
+
255
+ 3. transformAbc API基于Hvigor框架,用于处理abc文件路径。
256
+
257
+ 4. 为避免DevEco Studio、Hvigor和Native环境调用时可能出现的内存访问异常,建议使用worker_threads子线程执行插桩任务。
258
+
259
+ #### 场景示例
260
+
261
+ **场景一:生命周期函数打点**
262
+
263
+ **场景描述:**
264
+
265
+ 在开发过程中,精准定位组件行为往往需要对其生命周期进行监控。通过在关键生命周期函数中打点,开发者可以有效追踪组件行为,从而快速定位问题。
266
+
267
+ 以下示例以组件CompA为例,在aboutToAppear生命周期函数中进行插桩。
268
+
269
+ ArkTS源码如下所示:
270
+
271
+ ```
272
+ aboutToAppear(): void {
273
+ // Insert here: Set message to `Module[path: &entry/src/main/ets/pages/scene/LifeCycle&] - struct[name: ComponentA]
274
+ // - aboutToAppear is executed.`
275
+ }
276
+ ```
277
+
278
+ **实现步骤:**
279
+
280
+ 1. 初始化AbcManager实例。
281
+ 2. 定位目标函数。
282
+ 3. 执行前置插桩操作。
283
+ 4. 输出abc文件。
284
+
285
+ 代码如下:
286
+
287
+ ```
288
+ class Context {
289
+ static readonly PROJECT_MODULE: string = 'entry';
290
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/LifeCycle';
291
+ static readonly QUERY_CLASS_NAME: string = 'ComponentA';
292
+ static readonly QUERY_FUNCTION_NAME: string = 'aboutToAppear';
293
+ static readonly ATTRIBUTE_NAME: string = 'message';
294
+ static apiCallLog(moduleName: string, className: string): string {
295
+ return `Module[path: ${moduleName}] - struct[name: ${className}] - aboutToAppear is executed.`;
296
+ }
297
+ }
298
+
299
+ export class LifeCycleTask {
300
+ manager: AbcManager;
301
+ targetFunc: AbcFunction | null = null;
302
+
303
+ /**
304
+ * step1. init AbcManager
305
+ *
306
+ * @param manager AbcManager
307
+ */
308
+ constructor(manager: AbcManager) {
309
+ this.manager = manager;
310
+ }
311
+
312
+ run(): void {
313
+ this.getTargetFunction();
314
+ this.transform();
315
+ this.manager.flush();
316
+ }
317
+
318
+ /**
319
+ * step2. Position objective function
320
+ */
321
+ getTargetFunction(): void {
322
+ const functions = this.manager.query()
323
+ .projectModule(Context.PROJECT_MODULE)
324
+ .path(Context.QUERY_PATH)
325
+ .className(Context.QUERY_CLASS_NAME)
326
+ .functionName(Context.QUERY_FUNCTION_NAME)
327
+ .getFunction();
328
+ if (functions.length === 0) {
329
+ throw new Error('LifeCycle Task function not found');
330
+ }
331
+ this.targetFunc = functions[0];
332
+ }
333
+
334
+ /**
335
+ * step3. Perform pre-instrumentation.
336
+ */
337
+ transform(): void {
338
+ if (!this.targetFunc) {
339
+ return;
340
+ }
341
+ const isaKit = this.targetFunc.getIsaKit();
342
+ const instructions: Instruction[] = [];
343
+ const params = this.targetFunc.getParameters();
344
+ const moduleName = this.targetFunc.getParentModule().getName();
345
+ const className = this.targetFunc.getParentClass() == null ? '' : this.targetFunc.getParentClass().getName();
346
+ const loadStringInst = isaKit.createLdaString(Context.apiCallLog(moduleName, className));
347
+ const stobjbynameInst = isaKit.createStObjByName(loadStringInst, Context.ATTRIBUTE_NAME, params[params.length - 1]);
348
+ instructions.push(loadStringInst);
349
+ instructions.push(stobjbynameInst);
350
+ this.targetFunc.insertBefore(instructions);
351
+ this.targetFunc.apply();
352
+ }
353
+ }
354
+ ```
355
+
356
+ **场景二:函数耗时统计**
357
+
358
+ **场景描述:**
359
+
360
+ 开发者可以通过对函数定义点进行环绕插桩,定位源码中的性能问题。
361
+
362
+ 以下示例将对组件CompA中的aboutToAppear方法进行环绕插桩, 统计方法运行耗时。
363
+
364
+ ArkTS源码如下所示:
365
+
366
+ ```
367
+ async aboutToAppear(): Promise<void> {
368
+ // Insert here
369
+ // Assign startTime with Date.now()
370
+ await this.pseudoSyncOperation();
371
+ // Assign endTime with Date.now()
372
+ // Set message to `durations(ms): ${endTime}-${startTime}`
373
+ }
374
+ ```
375
+
376
+ **实现步骤:**
377
+
378
+ 1. 初始化AbcManager实例。
379
+ 2. 定位目标函数。
380
+ 3. 执行环绕插桩操作。
381
+ 4. 输出abc文件。
382
+
383
+ 代码如下:
384
+
385
+ ```
386
+ class Context {
387
+ static readonly PROJECT_MODULE: string = 'entry';
388
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/FunctionDuration';
389
+ static readonly QUERY_CLASS_NAME: string = 'CompA';
390
+ static readonly QUERY_FUNCTION_NAME: string = 'aboutToAppear';
391
+ static readonly API_IMPORT_NAME: string = 'geoLocationManager';
392
+ static readonly API_FUNCTION_NAME: string = 'getCurrentLocation';
393
+ static readonly REPLACE_MESSAGE: string = 'duration(ms): ';
394
+ static readonly ATTRIBUTE_NAME: string = 'message';
395
+ static readonly REPLACE_IMPORT_NAME: string = 'Date';
396
+ static readonly REPLACE_FUNCTION_NAME: string = 'now';
397
+ }
398
+
399
+ export class DurationTask {
400
+ manager: AbcManager;
401
+ targetFunc: AbcFunction | null = null;
402
+
403
+ /**
404
+ * step1. init AbcManager
405
+ *
406
+ * @param manager AbcManager
407
+ */
408
+ constructor(manager: AbcManager) {
409
+ this.manager = manager;
410
+ }
411
+
412
+ run(): void {
413
+ this.getTargetFunction();
414
+ this.doTransform();
415
+ this.manager.flush();
416
+ }
417
+
418
+ /**
419
+ * step3. Perform the wraparound instrumentation operation.
420
+ */
421
+ doTransform(): void {
422
+ const startTimeInst = this.doInsertBefore();
423
+ this.doInsertAfter(startTimeInst);
424
+ this.targetFunc?.apply();
425
+ }
426
+
427
+ doInsertAfter(startTimeInst: Instruction): void {
428
+ if (!this.targetFunc) {
429
+ return;
430
+ }
431
+ const isaKit = this.targetFunc.getIsaKit();
432
+ for (const inst of this.targetFunc.getInstructions()) {
433
+ const isReturn = isaKit.iGetOpcode(inst) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN ||
434
+ isaKit.iGetOpcode(inst) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED;
435
+ if (isReturn) {
436
+ const afterInsts = this.createAfterInsts(startTimeInst, isaKit);
437
+ isaKit.iInsertBefore(inst, afterInsts);
438
+ }
439
+ }
440
+ }
441
+
442
+ createAfterInsts(startTimeInst: Instruction, isaKit: IsaKit): Instruction[] {
443
+ const instructions: Instruction[] = [];
444
+ if (!this.targetFunc) {
445
+ return instructions;
446
+ }
447
+
448
+ const endTimeInsts = this.createTimeInstructions();
449
+ const subInst = isaKit.createSub2(startTimeInst, endTimeInsts[endTimeInsts.length - 1]);
450
+
451
+ const durationStrInst = isaKit.createLdaString(Context.REPLACE_MESSAGE);
452
+ const addInst = isaKit.createAdd2(subInst, durationStrInst);
453
+
454
+ const params = this.targetFunc.getParameters();
455
+ const stobjbynameInst = isaKit.createStObjByName(addInst, Context.ATTRIBUTE_NAME, params[params.length - 1]);
456
+
457
+ instructions.push(...endTimeInsts);
458
+ instructions.push(...[subInst, durationStrInst, addInst, stobjbynameInst]);
459
+ return instructions;
460
+ }
461
+
462
+ doInsertBefore(): Instruction {
463
+ const startTimeInsts = this.createTimeInstructions();
464
+ this.targetFunc?.insertBefore(startTimeInsts);
465
+ return startTimeInsts[startTimeInsts.length - 1];
466
+ }
467
+
468
+ createTimeInstructions(): Instruction[] {
469
+ const instructions: Instruction[] = [];
470
+ if (!this.targetFunc) {
471
+ return instructions;
472
+ }
473
+ const isaKit = this.targetFunc.getIsaKit();
474
+ const tryldglobalbyname = isaKit.createTryLdGlobalByName(Context.REPLACE_IMPORT_NAME);
475
+ const ldobjbyname = isaKit.createLdObjByName(tryldglobalbyname, Context.REPLACE_FUNCTION_NAME);
476
+ const callthis0 = isaKit.createCallThis0(ldobjbyname, tryldglobalbyname);
477
+
478
+ instructions.push(tryldglobalbyname);
479
+ instructions.push(ldobjbyname);
480
+ instructions.push(callthis0);
481
+
482
+ return instructions;
483
+ }
484
+
485
+ /**
486
+ * step2. Position objective function
487
+ */
488
+ getTargetFunction(): void {
489
+ const functions = this.manager.query()
490
+ .projectModule(Context.PROJECT_MODULE)
491
+ .path(Context.QUERY_PATH)
492
+ .className(Context.QUERY_CLASS_NAME)
493
+ .functionName(Context.QUERY_FUNCTION_NAME)
494
+ .getFunction();
495
+ if (functions.length === 0) {
496
+ throw new Error('Duration Task function not found.');
497
+ }
498
+ this.targetFunc = functions[0];
499
+ }
500
+ }
501
+ ```
502
+
503
+ **场景三:隐私API监控**
504
+
505
+ **场景描述:**
506
+
507
+ 开发者可以通过对调用点位置进行分析埋点,实现对重点API接口的调用监控。
508
+
509
+ 以下示例对地理位置获取操作进行调用监控,对geoLocationManager.getCurrentLocation()方法调用进行前置插桩。
510
+
511
+ ArkTS源码如下所示:
512
+
513
+ ```
514
+ getLocation(): void {
515
+ const request: geoLocationManager.SingleLocationRequest = {
516
+ locatingPriority: geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED,
517
+ locatingTimeoutMs: CommonConstants.LOCATING_TIMEOUT_MS
518
+ };
519
+ // Insert here: Set message to `Module[path: &entry/src/main/ets/pages/scene/PrivacyApi&]
520
+ // - struct[name: getLocation] - getCurrentLocation is executed.`
521
+ geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
522
+ this.longitude = location.longitude;
523
+ this.latitude = location.latitude;
524
+ }).catch((err: BusinessError) => {
525
+ Logger.error(TAG, `getLocation failed, code: ${err.code}, message: ${err.message}`);
526
+ LocationErrorUtil.locationFailedAlert(this.getUIContext(), err.code);
527
+ });
528
+ }
529
+ ```
530
+
531
+ **实现步骤:**
532
+
533
+ 1. 初始化AbcManager实例。
534
+ 2. 收集目标函数。
535
+ 3. 扫描函数指令,定位API调用点。
536
+ 4. 执行前置插桩操作。
537
+ 5. 输出abc文件。
538
+
539
+ 代码如下:
540
+
541
+ ```
542
+ class Context {
543
+ static readonly PROJECT_MODULE: string = 'entry';
544
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/PrivacyApi';
545
+ static readonly QUERY_CLASS_NAME: string = 'PrivacyApiPage';
546
+ static readonly QUERY_FUNCTION_NAME: string = 'getLocation';
547
+ static readonly API_IMPORT_NAME: string = 'geoLocationManager';
548
+ static readonly API_FUNCTION_NAME: string = 'getCurrentLocation';
549
+ static readonly ATTRIBUTE_NAME: string = 'message';
550
+ static apiCallLog(moduleName: string, className: string): string {
551
+ return `Module[path: ${moduleName}] - struct[name: ${className}] - getCurrentLocation is executed.`;
552
+ }
553
+ }
554
+
555
+ export class PrivacyApiScanTask {
556
+ manager: AbcManager;
557
+ targetFunc: AbcFunction | null = null;
558
+
559
+ /**
560
+ * step1. init AbcManager
561
+ *
562
+ * @param manager AbcManager
563
+ */
564
+ constructor(manager: AbcManager) {
565
+ this.manager = manager;
566
+ }
567
+
568
+ run(): void {
569
+ this.getTargetFunction();
570
+ this.transform();
571
+ this.manager.flush();
572
+ }
573
+
574
+ /**
575
+ * step2. Collect objective functions
576
+ */
577
+ getTargetFunction(): void {
578
+ const functions = this.manager.query()
579
+ .projectModule(Context.PROJECT_MODULE)
580
+ .path(Context.QUERY_PATH)
581
+ .className(Context.QUERY_CLASS_NAME)
582
+ .functionName(Context.QUERY_FUNCTION_NAME)
583
+ .getFunction();
584
+ if (functions.length === 0) {
585
+ throw new Error('PrivacyApiScan Task function not found');
586
+ }
587
+ this.targetFunc = functions[0];
588
+ }
589
+
590
+ isTargetApiCall(callInst: Instruction, params: { importName: string; functionName: string }): boolean {
591
+ if (!this.targetFunc) {
592
+ return false;
593
+ }
594
+ if (!this.targetFunc.getIsaKit().iIsCall(callInst)) {
595
+ return false;
596
+ }
597
+
598
+ const input0 = this.targetFunc.getIsaKit().iGetInput(callInst, 0);
599
+ const isTargetFunction = input0 && this.targetFunc.getIsaKit().iGetOpcode(input0) ===
600
+ IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME &&
601
+ this.targetFunc.getIsaKit().iGetString(input0) === params.functionName;
602
+ if (!isTargetFunction) {
603
+ return false;
604
+ }
605
+
606
+ const input1 = this.targetFunc.getIsaKit().iGetInput(callInst, 1);
607
+ if (!input1) {
608
+ return false;
609
+ }
610
+ const isTargetImport = this.targetFunc.getIsaKit().iGetOpcode(input1) ===
611
+ IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR &&
612
+ this.targetFunc.getIsaKit().iGetImportDescriptor(input1).getAlias() === params.importName;
613
+ return isTargetImport;
614
+ }
615
+
616
+ /**
617
+ * step3. Scans function instructions to locate API call points.
618
+ * step4. Perform pre-instrumentation operations.
619
+ */
620
+ transform(): void {
621
+ const instructions = this.targetFunc?.getInstructions();
622
+ if (!instructions || !this.targetFunc) {
623
+ return;
624
+ }
625
+
626
+ for (const inst of instructions) {
627
+ if (!this.isTargetApiCall(inst, { importName: Context.API_IMPORT_NAME, functionName: Context.API_FUNCTION_NAME })) {
628
+ continue;
629
+ }
630
+
631
+ const isaKit = this.targetFunc.getIsaKit();
632
+ const instructionsInsert: Instruction[] = [];
633
+ const params = this.targetFunc.getParameters();
634
+ const moduleName = this.targetFunc.getParentModule().getName();
635
+ const loadStringInst = isaKit.createLdaString(Context.apiCallLog(moduleName, this.targetFunc.getName()));
636
+ const stobjbynameInst = isaKit.createStObjByName(loadStringInst, Context.ATTRIBUTE_NAME, params[params.length - 1]);
637
+ instructionsInsert.push(loadStringInst);
638
+ instructionsInsert.push(stobjbynameInst);
639
+
640
+ isaKit.iInsertBefore(inst, instructionsInsert);
641
+ }
642
+ this.targetFunc?.apply();
643
+ }
644
+ }
645
+ ```
646
+
647
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/1c/v3/3UQpjPboTaq9Rt4-1E9EOg/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=1AF82D91AB1B4DCBE39D4EE13487810C6E1CA8363A9C029F7FAA744B211665D9)
648
+
649
+ 调用点分析通常不确定调用点位置,因此需要对范围内的方法进行全量指令扫描,范围限定越精确,定位调用点耗时越少。
650
+
651
+ **场景四:方法调用点替换**
652
+
653
+ **场景描述:**
654
+
655
+ 业务逻辑开发过程中,源码或三方库可能需要紧急修复异常,开发者可以通过调用点替换来增强API功能。
656
+
657
+ 以下示例将系统API geoLocationManager.getCurrentLocation()调用替换为自定义的GeoUtils.getLocation()方法。
658
+
659
+ ArkTS源码如下所示:
660
+
661
+ geoLocationManager.getCurrentLocation()为待替换API。
662
+
663
+ ```
664
+ getLocation(): void {
665
+ const request: geoLocationManager.SingleLocationRequest = {
666
+ locatingPriority: geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED,
667
+ locatingTimeoutMs: CommonConstants.LOCATING_TIMEOUT_MS
668
+ };
669
+ // Replace here: Replace geoLocationManager.getCurrentLocation with GeoUtils.getLocation
670
+ geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
671
+ this.longitude = location.longitude;
672
+ this.latitude = location.latitude;
673
+ this.message = TimeUtil.getNowWithHMS() + Context.MESSAGE_INFO;
674
+ }).catch((err: BusinessError) => {
675
+ Logger.error(TAG, `getLocationAddress failed, code: ${err.code}, message: ${err.message}`);
676
+
677
+ if (err.message === CommonConstants.CALL_TOO_FAST) {
678
+ this.message = TimeUtil.getNowWithHMS() + ': ' + err.message;
679
+ } else {
680
+ LocationErrorUtil.locationFailedAlert(this.getUIContext(), err.code);
681
+ }
682
+ });
683
+ }
684
+ ```
685
+
686
+ GeoUtils.getLocation()为替换API。
687
+
688
+ ```
689
+ export class GeoUtils {
690
+ private static lastInvokeTime: number = PageConstants.CONSTANT_VALUE_ZERO;
691
+ private static readonly MIN_INTERVAL: number = PageConstants.MINI_INTERVAL;
692
+
693
+ static async getLocation(
694
+ request?: geoLocationManager.CurrentLocationRequest | geoLocationManager.SingleLocationRequest
695
+ ): Promise<geoLocationManager.Location> {
696
+ const now = new Date().getTime();
697
+ if (now - GeoUtils.lastInvokeTime < GeoUtils.MIN_INTERVAL) {
698
+ return Promise.reject(new Error(CommonConstants.CALL_TOO_FAST));
699
+ }
700
+
701
+ GeoUtils.lastInvokeTime = now;
702
+ try {
703
+ return await geoLocationManager.getCurrentLocation(request);
704
+ } catch (error) {
705
+ throw new Error('Location retrieval failed');
706
+ }
707
+ }
708
+
709
+ static getLastInvokeTime(): number {
710
+ return GeoUtils.lastInvokeTime;
711
+ }
712
+
713
+ static resetLastInvokeTime(): void {
714
+ GeoUtils.lastInvokeTime = PageConstants.CONSTANT_VALUE_ZERO;
715
+ }
716
+
717
+ static init(): void {
718
+ }
719
+ }
720
+ ```
721
+
722
+ **实现步骤:**
723
+
724
+ 1. 初始化AbcManager实例。
725
+ 2. 定位目标函数。
726
+ 3. 扫描函数指令,定位API调用点。
727
+ 4. 引入外部替换API模块。
728
+ 5. 执行替换插桩操作。
729
+ 6. 输出abc文件。
730
+
731
+ 代码如下:
732
+
733
+ ```
734
+ class Context {
735
+ static readonly PROJECT_MODULE: string = 'entry';
736
+ static readonly ASPECT_PATH: string = 'src/main/ets/common/GeoUtils';
737
+ static readonly ASPECT_FUNCTION_NAME: string = 'getLocation';
738
+ static readonly ASPECT_IMPORT_NAME: string = 'GeoUtils';
739
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/CallReplace';
740
+ static readonly QUERY_FUNCTION_NAME: string = 'getLocation';
741
+ static readonly API_IMPORT_NAME: string = 'geoLocationManager';
742
+ static readonly API_FUNCTION_NAME: string = 'getCurrentLocation';
743
+ static readonly REPLACE_IMPORT_NAME: string = 'GeoUtils';
744
+ }
745
+
746
+ export class CallReplaceTask {
747
+ manager: AbcManager;
748
+ targetFunc: AbcFunction | null = null;
749
+ aspectFunc: AbcFunction | null = null;
750
+ importDescriptor: ImportDescriptor | null = null;
751
+
752
+ /**
753
+ * step1. init AbcManager
754
+ *
755
+ * @param manager AbcManager
756
+ */
757
+ constructor(manager: AbcManager) {
758
+ this.manager = manager;
759
+ }
760
+
761
+ run(): void {
762
+ this.getTargetFunction();
763
+ this.getAspectFunction();
764
+ this.getImportDescriptor();
765
+ this.doTransform();
766
+ this.manager.flush();
767
+ }
768
+
769
+ /**
770
+ * step4. Scans function instructions to locate API call points.
771
+ * step5. Perform the replacement and instrumentation operation.
772
+ */
773
+ doTransform(): void {
774
+ if (!this.targetFunc || !this.importDescriptor || !this.aspectFunc) {
775
+ return;
776
+ }
777
+
778
+ const isaKit = this.targetFunc.getIsaKit();
779
+ const insts = this.targetFunc.getInstructions();
780
+
781
+ if (!insts) {
782
+ return;
783
+ }
784
+
785
+ for (const inst of insts) {
786
+ if (!this.isTargetApiCall(inst,
787
+ { importName: Context.API_IMPORT_NAME, functionName: Context.API_FUNCTION_NAME })) {
788
+ continue;
789
+ }
790
+ const importDesc = isaKit.createLdExternalModuleVar(this.importDescriptor);
791
+ const parentClass = this.aspectFunc.getParentClass();
792
+
793
+ if (!parentClass) {
794
+ continue;
795
+ }
796
+
797
+ const myAspect =
798
+ isaKit.createThrowUndefinedIfHoleWithName(importDesc, parentClass.getName());
799
+ const replaceAdd = isaKit.createLdObjByName(myAspect, this.aspectFunc.getName());
800
+ isaKit.iInsertBefore(inst, [importDesc, myAspect, replaceAdd]);
801
+ isaKit.iSetInput(inst, 0, replaceAdd);
802
+ isaKit.iSetInput(inst, 1, importDesc);
803
+ }
804
+ this.targetFunc.apply();
805
+ }
806
+
807
+ isTargetApiCall(callInst: Instruction, params: { importName: string; functionName: string }): boolean {
808
+ if (!this.targetFunc) {
809
+ return false;
810
+ }
811
+ const isaKit = this.targetFunc.getIsaKit();
812
+ if (!isaKit.iIsCall(callInst)) {
813
+ return false;
814
+ }
815
+
816
+ const input0 = isaKit.iGetInput(callInst, 0);
817
+ const isTargetFunction =
818
+ input0 && isaKit.iGetOpcode(input0) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME &&
819
+ isaKit.iGetString(input0) === params.functionName;
820
+ if (!isTargetFunction) {
821
+ return false;
822
+ }
823
+
824
+ const input1 = isaKit.iGetInput(callInst, 1);
825
+ if (!input1) {
826
+ return false;
827
+ }
828
+ const isTargetImport =
829
+ isaKit.iGetOpcode(input1) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR &&
830
+ isaKit.iGetImportDescriptor(input1).getAlias() === params.importName;
831
+
832
+ return isTargetImport;
833
+ }
834
+
835
+ getImportDescriptor(): void {
836
+ if (!this.targetFunc || !this.aspectFunc) {
837
+ return;
838
+ }
839
+ const isa = this.targetFunc.getIsaKit();
840
+ this.importDescriptor =
841
+ isa.getOrAddImportDescriptor(this.targetFunc.getParentModule(), this.aspectFunc.getParentModule(),
842
+ Context.REPLACE_IMPORT_NAME,
843
+ Context.REPLACE_IMPORT_NAME);
844
+ }
845
+
846
+ /**
847
+ * step3. Introduce an external API replacement module
848
+ */
849
+ getAspectFunction(): void {
850
+ const functions = this.manager.query()
851
+ .projectModule(Context.PROJECT_MODULE)
852
+ .path(Context.ASPECT_PATH)
853
+ .functionName(Context.ASPECT_FUNCTION_NAME)
854
+ .getFunction();
855
+ if (functions.length === 0) {
856
+ throw new Error('aspect function not found');
857
+ }
858
+ this.aspectFunc = functions[0];
859
+ }
860
+
861
+ /**
862
+ * step2. Position objective function
863
+ */
864
+ getTargetFunction(): void {
865
+ const functions = this.manager.query()
866
+ .projectModule(Context.PROJECT_MODULE)
867
+ .path(Context.QUERY_PATH)
868
+ .functionName(Context.QUERY_FUNCTION_NAME)
869
+ .getFunction();
870
+ if (functions.length === 0) {
871
+ throw new Error('CallReplace Task function not found.');
872
+ }
873
+ this.targetFunc = functions[0];
874
+ }
875
+ }
876
+ ```
877
+
878
+ **场景五:关键属性修改**
879
+
880
+ **场景描述:**
881
+
882
+ 当三方框架出现运行时缺陷,某些属性的配置不符合预期,开发者可以通过对字节码指令的修改,修复相关问题。
883
+
884
+ 以下示例通过对字节码指令的编辑,实现对message属性的修改。
885
+
886
+ ArkTS源码如下所示:
887
+
888
+ ```
889
+ changeMessage(): void {
890
+ this.logInfo = Context.MESSAGE_INFO;
891
+ // Insert here: Set this.message to "This is New Title"
892
+ }
893
+ ```
894
+
895
+ **实现步骤:**
896
+
897
+ 1. 初始化AbcManager实例。
898
+ 2. 定位目标函数。
899
+ 3. 执行指令编辑操作。
900
+ 4. 输出abc文件。
901
+
902
+ 代码如下:
903
+
904
+ ```
905
+ class Context {
906
+ static readonly PROJECT_MODULE: string = 'entry';
907
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/KeyAttribute';
908
+ static readonly QUERY_CLASS_NAME: string = 'KeyAttributePage';
909
+ static readonly QUERY_FUNCTION_NAME: string = 'changeMessage';
910
+ static readonly REPLACE_MESSAGE: string = 'This is New Title!';
911
+ static readonly ATTRIBUTE_NAME: string = 'message';
912
+ }
913
+
914
+ export class KeyAttributeModifyTask {
915
+ manager: AbcManager;
916
+ targetFunc: AbcFunction | null = null;
917
+
918
+ /**
919
+ * step1. init AbcManager
920
+ *
921
+ * @param manager AbcManager
922
+ */
923
+ constructor(manager: AbcManager) {
924
+ this.manager = manager;
925
+ }
926
+
927
+ run(): void {
928
+ this.getTargetFunction();
929
+ this.transform();
930
+ this.manager.flush();
931
+ }
932
+
933
+ /**
934
+ * step2. Position objective function
935
+ */
936
+ getTargetFunction(): void {
937
+ const functions = this.manager.query()
938
+ .projectModule(Context.PROJECT_MODULE)
939
+ .path(Context.QUERY_PATH)
940
+ .className(Context.QUERY_CLASS_NAME)
941
+ .functionName(Context.QUERY_FUNCTION_NAME)
942
+ .getFunction();
943
+ if (functions.length === 0) {
944
+ throw new Error('KeyAttributeModify Task function not found');
945
+ }
946
+ this.targetFunc = functions[0];
947
+ }
948
+
949
+ /**
950
+ * step3. Perform the instruction editing operation.
951
+ */
952
+ transform(): void {
953
+ if (!this.targetFunc) {
954
+ return;
955
+ }
956
+ const isaKit = this.targetFunc.getIsaKit();
957
+ const instructions: Instruction[] = [];
958
+ const params = this.targetFunc.getParameters();
959
+ const loadStringInst = isaKit.createLdaString(Context.REPLACE_MESSAGE);
960
+ const stobjbynameInst = isaKit.createStObjByName(loadStringInst, Context.ATTRIBUTE_NAME, params[params.length - 1]);
961
+ instructions.push(loadStringInst);
962
+ instructions.push(stobjbynameInst);
963
+ this.targetFunc.insertBefore(instructions);
964
+ this.targetFunc.apply();
965
+ }
966
+ }
967
+ ```
968
+
969
+ **场景六:点击事件埋点**
970
+
971
+ **场景描述:**
972
+
973
+ 开发者可通过在点击事件回调函数中插桩,对用户点击行为进行监控和统计,实现用户行为数据的自动采集。
974
+
975
+ 以下示例对Button组件的onClick()事件回调函数进行前置插桩。
976
+
977
+ ArkTS源码如下所示:
978
+
979
+ ```
980
+ Button($r('app.string.event_onclick'))
981
+ .attributeModifier(new ButtonStyles())
982
+ .onClick(() => {
983
+ // Insert here: Set message to `Module[path: &entry/src/main/ets/pages/scene/EventCallbackBeforeTs&]
984
+ // -onclick event is triggered.`
985
+ });
986
+ ```
987
+
988
+ **实现步骤:**
989
+
990
+ 1. 初始化AbcManager实例。
991
+ 2. 收集目标函数。
992
+ 3. 扫描函数指令,定位回调函数。
993
+ 4. 执行前置插桩操作。
994
+ 5. 输出abc文件。
995
+
996
+ 代码如下:
997
+
998
+ ```
999
+ class Context {
1000
+ static readonly PROJECT_MODULE: string = 'entry';
1001
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/EventCallbackBeforeTs';
1002
+ static readonly QUERY_FUNCTION_NAME: string = 'initialRender';
1003
+ static readonly API_IMPORT_NAME: string = 'Button';
1004
+ static readonly API_FUNCTION_NAME: string = 'onClick';
1005
+ static readonly ATTRIBUTE_NAME: string = 'message';
1006
+
1007
+ static apiCallLog(moduleName: string): string {
1008
+ return `Module[path: ${moduleName}] - onclick event is triggered.`;
1009
+ }
1010
+ }
1011
+
1012
+ export class EventCbTask {
1013
+ manager: AbcManager;
1014
+ targetFuncs: AbcFunction[] = [];
1015
+
1016
+ /**
1017
+ * step1. init AbcManager
1018
+ *
1019
+ * @param manager AbcManager
1020
+ */
1021
+ constructor(manager: AbcManager) {
1022
+ this.manager = manager;
1023
+ }
1024
+
1025
+ run(): void {
1026
+ this.getTargetFunction();
1027
+ const targetCbFuncs: AbcFunction[] = [];
1028
+ for (const func of this.targetFuncs) {
1029
+ this.collectCallBackFuncs(func, targetCbFuncs);
1030
+ }
1031
+
1032
+ for (const cbFunc of targetCbFuncs) {
1033
+ this.doTransform(cbFunc);
1034
+ }
1035
+ this.manager.flush();
1036
+ }
1037
+
1038
+ /**
1039
+ * step4. Perform pre-instrumentation operations.
1040
+ *
1041
+ * @param cbFunc AbcFunction
1042
+ */
1043
+ doTransform(cbFunc: AbcFunction): void {
1044
+ const moduleName = cbFunc.getParentModule().getName();
1045
+ const isaKit = cbFunc.getIsaKit();
1046
+ for (const inst of cbFunc.getInstructions()) {
1047
+ const isReturn = isaKit.iGetOpcode(inst) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN ||
1048
+ isaKit.iGetOpcode(inst) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED;
1049
+ if (isReturn) {
1050
+ const ldlexvarInst = isaKit.createLdLexVar(0, 0);
1051
+ const loadStringInst = isaKit.createLdaString(Context.apiCallLog(moduleName));
1052
+ const stobjbynameInst = isaKit.createStObjByName(loadStringInst, Context.ATTRIBUTE_NAME, ldlexvarInst);
1053
+ const instructions: Instruction[] = [];
1054
+ instructions.push(ldlexvarInst);
1055
+ instructions.push(loadStringInst);
1056
+ instructions.push(stobjbynameInst);
1057
+ isaKit.iInsertBefore(inst, instructions);
1058
+ }
1059
+ }
1060
+
1061
+ cbFunc.apply();
1062
+ }
1063
+
1064
+ /**
1065
+ * step3. Scans function instructions to locate the callback function.
1066
+ *
1067
+ * @param targetFunc AbcFunction
1068
+ * @param targetCbFuncs AbcFunction[]
1069
+ */
1070
+ collectCallBackFuncs(targetFunc: AbcFunction, targetCbFuncs: AbcFunction[]): void {
1071
+ const instructions = targetFunc.getInstructions();
1072
+ const isaKit = targetFunc.getIsaKit();
1073
+ for (const inst of instructions) {
1074
+ if (!this.isTargetApiCall(targetFunc, inst, { importName: Context.API_IMPORT_NAME, functionName: Context.API_FUNCTION_NAME })) {
1075
+ continue;
1076
+ }
1077
+ const cbFunc = this.getCbFunc(inst, isaKit);
1078
+ if (!cbFunc) {
1079
+ throw new Error('Failed to get callback function');
1080
+ }
1081
+ targetCbFuncs.push(cbFunc);
1082
+ }
1083
+ }
1084
+
1085
+ isTargetApiCall(targetFunc: AbcFunction, callInst: Instruction,
1086
+ params: { importName: string; functionName: string }): boolean {
1087
+ const isaKit = targetFunc.getIsaKit();
1088
+ if (!isaKit.iIsCall(callInst)) {
1089
+ return false;
1090
+ }
1091
+
1092
+ const input0 = isaKit.iGetInput(callInst, 0);
1093
+ if (!input0) {
1094
+ return false;
1095
+ }
1096
+ const isTargetFunction = input0 && isaKit.iGetOpcode(input0) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME &&
1097
+ isaKit.iGetString(input0) === params.functionName;
1098
+ if (!isTargetFunction) {
1099
+ return false;
1100
+ }
1101
+ const input1 = isaKit.iGetInput(callInst, 1);
1102
+ if (!input1) {
1103
+ return false;
1104
+ }
1105
+ const isTargetImport = isaKit.iGetOpcode(input1) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME &&
1106
+ isaKit.iGetString(input1) === params.importName;
1107
+ return isTargetImport;
1108
+ }
1109
+
1110
+ getCbFunc(callInst: Instruction, isaKit: IsaKit): AbcFunction | undefined {
1111
+ const inputs = isaKit.iGetInputs(callInst);
1112
+ for (const input of inputs) {
1113
+ if (isaKit.iGetOpcode(input) === IsaApiDynamicOpcode.ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC) {
1114
+ return isaKit.iGetFunction(input) ?? undefined;
1115
+ }
1116
+ }
1117
+ return undefined;
1118
+ }
1119
+
1120
+ /**
1121
+ * step2. Collect the objective function.
1122
+ */
1123
+ getTargetFunction(): void {
1124
+ const functions = this.manager.query()
1125
+ .projectModule(Context.PROJECT_MODULE)
1126
+ .path(Context.QUERY_PATH)
1127
+ .functionName(Context.QUERY_FUNCTION_NAME)
1128
+ .getFunction();
1129
+ if (functions.length === 0) {
1130
+ throw new Error('EventCb Task function not found');
1131
+ }
1132
+ const children = functions[0].getNestedAnonymousCallbacks();
1133
+ if (children.length === 0) {
1134
+ throw new Error('EventCb Task initialRender function has no nested anonymous callback');
1135
+ }
1136
+ this.targetFuncs.push(...children);
1137
+ }
1138
+ }
1139
+ ```
1140
+
1141
+ ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f0/v3/Ek-MII49SIGL5jj_XNAWCw/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260623T075536Z&HW-CC-Expire=86400&HW-CC-Sign=BED3CD3D7A2E638E335FB198E1F7B7AA7D3D4244B32DAB16C87947AC63DDFC4A)
1142
+
1143
+ **initialRender**函数是鸿蒙应用页面级渲染的入口函数,onClick回调通常以匿名函数形式嵌套在其中。
1144
+
1145
+ **场景七:方法入参校验**
1146
+
1147
+ **场景描述:**
1148
+
1149
+ 在开发过程中,方法入参的合法性校验是保证程序健壮性的重要手段。当需要在不修改源码的情况下对方法参数进行统一校验,或对三方库的方法调用进行监控时,可以通过字节码插桩技术实现。
1150
+
1151
+ 以下示例通过字节码插桩,实现在saveUser方法入口处校验age属性的合法性(age>=0 and age<=150)。
1152
+
1153
+ ```
1154
+ saveUser(name: string, age: number): void {
1155
+ // Insert here
1156
+ // Check if age < 0 or age > 150, assign message to "save user failed, age abnormal" and return
1157
+ this.message = 'name:' + name + ' ' + 'age:' + age + '\n';
1158
+ }
1159
+ ```
1160
+
1161
+ **实现步骤:**
1162
+
1163
+ 1. 初始化AbcManager实例。
1164
+ 2. 定位目标函数。
1165
+ 3. 执行block插桩操作。
1166
+ 4. 输出abc文件。
1167
+
1168
+ 代码如下:
1169
+
1170
+ ```
1171
+ class Context {
1172
+ static readonly PROJECT_MODULE: string = 'entry';
1173
+ static readonly QUERY_PATH: string = 'src/main/ets/pages/scene/MethodParameter';
1174
+ static readonly QUERY_CLASS_NAME: string = 'MethodParameterPage';
1175
+ static readonly QUERY_FUNCTION_NAME: string = 'saveUser';
1176
+ static readonly REPLACE_MESSAGE: string = 'save user failed, age abnormal.';
1177
+ static readonly ATTRIBUTE_NAME: string = 'message';
1178
+ static readonly AGE_MAX: number = 150;
1179
+ }
1180
+
1181
+ export class MethodParameterValidateTask {
1182
+ manager: AbcManager;
1183
+ targetFunc: AbcFunction | null = null;
1184
+
1185
+ /**
1186
+ * step1. init AbcManager
1187
+ *
1188
+ * @param manager AbcManager
1189
+ */
1190
+ constructor(manager: AbcManager) {
1191
+ this.manager = manager;
1192
+ }
1193
+
1194
+ run(): void {
1195
+ this.getTargetFunction();
1196
+ this.transform();
1197
+ this.manager.flush();
1198
+ }
1199
+
1200
+ /**
1201
+ * step2. Position objective function
1202
+ */
1203
+ getTargetFunction(): void {
1204
+ const functions = this.manager.query()
1205
+ .projectModule(Context.PROJECT_MODULE)
1206
+ .path(Context.QUERY_PATH)
1207
+ .className(Context.QUERY_CLASS_NAME)
1208
+ .functionName(Context.QUERY_FUNCTION_NAME)
1209
+ .getFunction();
1210
+ if (functions.length === 0) {
1211
+ throw new Error('MethodParameterValidate Task function not found');
1212
+ }
1213
+ this.targetFunc = functions[0];
1214
+ }
1215
+
1216
+ /**
1217
+ * step3. Perform block instrumentation.
1218
+ */
1219
+ transform(): void {
1220
+ if (!this.targetFunc) {
1221
+ return;
1222
+ }
1223
+ const isaKit = this.targetFunc.getIsaKit();
1224
+
1225
+ const instructions: Instruction[] = [];
1226
+ const params = this.targetFunc.getParameters();
1227
+ if (params.length < 3) {
1228
+ return;
1229
+ }
1230
+ const loadStringInst = isaKit.createLdaString(Context.REPLACE_MESSAGE);
1231
+ const stobjbynameInst = isaKit.createStObjByName(loadStringInst, Context.ATTRIBUTE_NAME, params[2]);
1232
+ instructions.push(loadStringInst);
1233
+ instructions.push(stobjbynameInst);
1234
+ instructions.push(isaKit.createReturnUndefined());
1235
+
1236
+ const startBlock = isaKit.bGetStartBlock();
1237
+ const succBlocks = isaKit.bGetSuccBlocks(startBlock);
1238
+ const const0 = isaKit.iCreateConstantU64(0);
1239
+ const const02 = isaKit.iCreateConstantU64(0);
1240
+
1241
+ const trueBB = succBlocks[0];
1242
+ isaKit.bEraseSuccBlock(startBlock, 0);
1243
+ const falseBB = isaKit.bCreateEmptyBlock();
1244
+ isaKit.bAppendSuccBlock(falseBB, isaKit.bGetEndBlock());
1245
+ isaKit.bAddInstructionsBack(falseBB, instructions);
1246
+
1247
+ const ifBB = isaKit.bCreateEmptyBlock();
1248
+ const lessInst = isaKit.createLess(const0, params[params.length - 1]);
1249
+ const callruntimeTrueInst = isaKit.createCallRuntimeIsTrue(lessInst);
1250
+ const ifInst =
1251
+ isaKit.createIf(callruntimeTrueInst, IsaApiDynamicConditionCode.ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_EQ);
1252
+ isaKit.iSetInput(ifInst, 1, const02);
1253
+
1254
+ const ifBB2 = isaKit.bCreateEmptyBlock();
1255
+ const const150 = isaKit.iCreateConstantU64(Context.AGE_MAX);
1256
+ const lessInst2 = isaKit.createGreater(const150, params[params.length - 1]);
1257
+ const callruntimeFalseInst2 = isaKit.createCallRuntimeIsFalse(lessInst2);
1258
+ const ifInst2 =
1259
+ isaKit.createIf(callruntimeFalseInst2, IsaApiDynamicConditionCode.ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_NE);
1260
+ isaKit.iSetInput(ifInst2, 1, const02);
1261
+
1262
+ isaKit.bAddInstructionsBack(ifBB, [lessInst, callruntimeTrueInst, ifInst]);
1263
+ isaKit.bAddInstructionsBack(ifBB2, [lessInst2, callruntimeFalseInst2, ifInst2]);
1264
+ isaKit.bAppendSuccBlock(startBlock, ifBB);
1265
+ isaKit.bAppendSuccBlock(ifBB, ifBB2);
1266
+ isaKit.bAppendSuccBlock(ifBB, falseBB);
1267
+ isaKit.bAppendSuccBlock(ifBB2, trueBB);
1268
+ isaKit.bAppendSuccBlock(ifBB2, falseBB);
1269
+
1270
+ this.targetFunc.apply();
1271
+ }
1272
+ }
1273
+ ```
1274
+
1275
+ ----结束↵
1276
+
1277
+ #### 示例代码
1278
+
1279
+ - [基于AbcKitTS实现字节码插桩](https://gitcode.com/HarmonyOS_Samples/abckit-ts)