dex2oat编译模式、触发场景、命令强制执行
dex2oat简单理解就是把delvik虚拟机的可执行文件dex转化成AndroidRuntime虚拟机的可执行文件oat。
Android T版本由PKMS下发命令、native层进程installd负责具体执行dex2oat操作。installd回去调用dex2oat64完成编译工作,可以将dex2oat64理解成一个程序。源码路径:/apex/com.android.art/bin/dex2oat6
一、dex2oat的几种常见的编译模式
ab-ota ab升级时进行OTA prepare编译
speed-profile bg-dexopt 手机进入idle状态(充电灭屏半小时以上)编译
verify boot 开机过程中编译
speed core-app 开机过程或者充电时候的核心应用
quicken first-boot 首次开机过程中编译(刷机、OTA升级)
inactive verify idle时对10天内未使用过的应用转入此状态
install speed-profile 安装时编译
shared speed 通过package usage得到,被其他应用加载的dex
unknown run-from-apk 应用首次启动后编译,一般需要一定时间
first-boot: 首次开机或恢复出厂设置后的第一次开机,对应优化方式:speed-profile
boot:大部分时候是OTA升级后开机,可能在开机动画阶段,也可能是进入桌面后后台执行,对应优化方式:verify
core-app: 手软新增场景,针对TOP100应用做bg-dexopt优化时,采用此方式,对应的优化方式:speed
install:应用安装场景,对应优化方式:speed-profile
bg-dexopt: 系统记录热代码(包括apk和插件中的dex)后,在息屏idle状态下执行优化,对应优化方式:speed-profile
ab-ota:若系统采用A/B分区,在准备升级过程中,提前对应用做dexopt优化,对应优化方式:speed-profile
inactive:空间不足时,取消部分应用已经做的dexopt优化,重新做低级别的优化,对应优化方式:verify
shared:若当前优化应用执行方式为speed-profile且此应用有被其他应用加载的情况,则升级优化方式为speed
verify:只运行 DEX 代码验证。
quicken:运行 DEX 代码验证,并优化一些 DEX 指令,以获得更好的解释器性能。
speed-profile:运行 DEX 代码验证,并对配置文件中列出的方法进行 AOT 编译。
speed:运行 DEX 代码验证,并对所有方法进行 AOT 编译。
speed和speed-profile区别
speed和speed-profile是Android 编译模式中的两种选项。speed是一种编译模式,旨在最大化运行时性能,而speed-profile则是一种部分编译模式,根据profile记录的热点函数来编译,也是为了最大化运行时性能。
speed-profile是基于profile的quicken,即profile-guilde部分是speed,其余是quicken。但是安装的时候没啥profile,约等于quicken。profile是靠后续收集的,debug版本1000次,user版本10000次,会记录到每个进程的prof文件里。
每个app的profile文件都位于/data/misc/profiles/cur/userId/包名/primary.prof,profile文件用来记录运行比较频繁的代码,用来进行 profile-guide 编译,使得 dex2oat编译代码更精准。
1、run-from-apk
dex文件包含于apk文件中,apk是一个压缩包,run-from-apk的意思就是运行APP的时候再从apk中把dex解压出来,运行的时候边运行边把dex解释成AndroidRuntime可以执行的文件。这种模式显然是最慢的。一般不会有这种模式出现,下面三种特殊情况会出现这种模式:
①应用做dex2oat有花花似,为了保证系统稳定性,中断了优化。
②Android R上应用如果7天或者更长时间未使用,升级过程中会被认为是不常用应用,为了节省资源不优化这类应用。升级后这类应用将是run-from-apk状态。
③处在debug模式的应用不会进行dex2oat优化,会保持run-from-apk。
T上的项目将不会出现run-from-apk这种模式了。
2、extract
这种模式会将apk中的dex提前解压释放出来,这类性能比run-from-apk好一些,毕竟省去了解压apk的过程。S上进行ota升级后,会对升级过程中未选中的应用进行extract(7天或者更长时间未使用)。执行此模式的时候不涉及到编译,因此占用的系统资源相比其他编译模式会少很多。但是也正是由于本身没有任何除了解压之外的预处理,因此运行的时候所有的类加载都要verify,且只能解释执行,速度也比较慢。
3、verity,quicken
这两种模式相比前面的两种更进一步,verify模式不仅会将dex文件提前释放出来,还会提前做pre verify,生成vdex,从而省去运行的时候verify的步骤;quciken模式编译的时候会把dex文件编译成quciken code,quciken code是没有使用AndroidRuntime虚拟机的时候,系统dexopt的产物。但是这两种都不会编译成ota code。 quicken模式已在S上移除,R上quicken等效于S上的verify。
4、speed
系统的核心应用或者ShareuserID的应用将会是speed模式。这类模式的时候系统会对限定大小的方法以及class进行oat编译,生成对应的机器码。基本上是能编译的都编译了,可以说饥不择食了,因此十分耗时和耗费CPU资源。此类模式在应用启动时是相对来说很快的模式了。简单来理解就是编译了dex的大部分文件了。
5、everying
顾名思义就是把dex文件全部一丝不留编译成机械码,比speed还狠。特点是运行最快,编译文件占用存储空间最大。也因为占用系统资源很大,编译文件很大,这种编译模式不存在于正常的应用中,只存在于debug模式的应用中。
6、speed-profile
这是现在最常见的一种编译模式,它会根据用户的使用习惯,不断的进行再编译(当然再编译是要满足条件的)。它会将用户经常打开的页面中的类和经常使用的方法记录到profile文件中,用profile文件去指导编译,同时对于常用的class和string类型还会保存到对应的art文件中,用以启动加速。当应用进程起来的时候,会同时启动jit线程,而jit会对当前进程中的hot method进行run time编译,同时也会记录保存需要编译的方法和类名,这个就是profile文件。此类模式编译的结果是oat code。 此类模式由于有了profile的引入,因此编译触发比较特殊。是根据profile记录的差异与大小来触发编译。比如当前使用的应用记录了1000个方法,如果继续使用后记录变成了1100个方法,这个时候仍然不会触发编译(默认是20%增加)。如果profile记录的方法数量小于100或者class数量小于50,系统也会认为没有编译的必要。也正是因为引入了profile的编译,同样的系统版本,同样的应用版本,不同人使用的习惯不同,可能应用的odex文件编译大小也不同。理论上随着应用使用越久,profile信息将越完善,也越稳定,应用性能将越来越好。
static constexpr uint32_t kMinNewMethodsPercentChangeForCompilation = 20;
static constexpr uint32_t kMinNewClassesPercentChangeForCompilation = 20;
static constexpr const uint32_t kMinNewMethodsForCompilation = 100;
static constexpr const uint32_t kMinNewClassesForCompilation = 50

如果有root权限或者可以拿到应用的profile文件,有两个地方会保存profile,运行时写入的地方是:/data/misc/profiles/cur/0/包名/primary.prof, 编译时使用的是/data/misc/profiles/ref/包名/primary.prof。 采用speed-profile模式编译的应用,在data/dalvik-cache/arm64中一定会产生art文件,可以用这一点去判断编译模式,当然最好用的是用dumpsys命令去查看,使用dumpsys package +应用包名,可以看到应用的所有信息,包括UID、安装时间、权限信息、签名信息、dex2oat的状态。
7、vdex
为何要搞出个vdex文件?目的是为了避免不必要的验证Dex 文件合法性的过程,首次安装进行dex2oat时,会校验Dex 文件各个section的合法性,生成vdex文件,下次启动应用的时候就可以不用去校验。odex文件来自于vdex,odex+vdex=完整的apk dex信息。我对vdex的理解就是pre verify dex,就是做过verify验证的dex文件。 Android S 之后,谷歌更新了vdex格式,致使vdex复用成为可能。在S 之前,应用安装的时候会生成vdex,启动编译,或者充电编译时,会再生成一次,浪费系统资源。S上谷歌改进了这点,当二次编译的时候,如果是同一个apk,vdex将能够复用。 应用dex2oat成为vdex模式的原因,有且只有odex失效才会是vdex状态(注:odex是从vdex中提取内容组成)。有以下几种场景: 应用已经有odex,此时进行了mainline更新,重启后,由于mainline更新了,odex的依赖也需要更新,此时odex会失效,应用会变成vdex状态。 系统进行ota更新,应用不再常用应用内(七天内使用过),此类应用不会再升级过程中二次优化,升级完成后将是vdex状态。 需要注意。有一种vdex状态是异常的。比如桌面launcher,systemui这类在固件内已经是prebuild编译的应用,这类应用刷机后如果是vdex状态,那么意味着固件编译的时候odex有问题。(odex值dex2oat的结果)
8、总结
从上面介绍的这几种常见的编译模式中可以看出,谷歌设计这几种编译模式的目的,是让我们基于性能的角度可以自主控制dex2oat的编译模式,其策略是以空间换取时间, 想要应用启动得越快,就需要提前编译更多的方法和类,当然编译产生的文件占用的存储空间也会越来越大。
二、dex2oat常见的触发场景
1、内置应用
内置应用有两种方式可以修改prebuilt出来的模式。
第一种,配置自己的mk文件配置对应的模式,mk文件中加入如下修改LOCAL_DEX_PREOPT_FLAGS += --compiler-filter=speed
第二种方法,在PRODUCT_DEXPREOPT_SPEED_APPS配置文件中添加对应的apk model名字修改完成后,刷机后可以通过adb shell dumpsys package + 包名 查看其中的dex status 与reason确认是否配置成功,其中reason是prebuilt。
2、应用安装
安装触发场景根据APK来源不同分为三种:
2.1、 非谷歌商店,非应用商店安装
此类安装后通过dump查看 reason = install status = speed-profile
2.2、 谷歌商店安装
谷歌商店安装部分应用(谷歌商店内部有名单)安装后 reason=install-dm。此类应用是由于谷歌商店下发了profile文件,在安装过程中使用了profile。因此installd-dm一般是安装完成后就有比较好的性能。相当于已经进行过了二次编译,但也是因为这样,install-dm的安装时间比较长。
reason = install-dm status = speed-profile
3、灭屏充电
灭屏充电这种触发场景是通过job scheduler完成的,简单来说jobscheduler就是一种系统委托,当手机灭屏充电的时候,达到某一个job的触发条件,job就会自动执行起来。常见的委托条件,充电条件,idle条件,网络等。API介绍:https://developer.android.com/reference/android/app/job/JobInfo.Builder
这里着重说下idle条件,这里是原生系统定义的,目前R之前的idle状态是灭屏71分钟,R之后的版本为31分钟。也就是当灭屏时间满足半个小时的时候,所有委托idle状态的job就该起来干活了。
如何避免灭屏充电编译:
1、进行一晚上灭屏充电,进行灭屏充电编译。
2、通过命令禁止,上层重启后起作用。整机重启后失效。
adb shell setprop pm.dexopt.disable_bg_dexopt true adb shell am restart
3、停止job,每次开机设置一下,也是整机重启就失效。
adb shell cmd jobscheduler cancel android 800
adb shell cmd jobscheduler cancel android 801
当灭屏充电编译发起的时候,必然有BackgroundDexOptService 的日志打印,其中可以看到当前编译的状态(R上日志可能要少一些)。
充电编译开始:
BackgroundDexOptService:Performing idle optimizations
充电类型:
BackgroundDexOptService: schargeType is x 其中 x 如果是1 ,则是vooc充电 ,3或者4是pdqc充电,5是无线充电 充电电流设置: charging feature is on 是记录的上层设置的充电电流
充电编译中断:
BackgroundDexOptService: abort by thermal type


4、升级
升级过程会根据升级之前应用的使用记录进行选择编译,当前系统定义的是7天内未使用过的应用为不常用应用,这类应用将不在升级过程中进行升级编译。而对于升级编译的应用,为了平衡性能与升级时间,R上默认将采用quicken模式 S上默认是verify模式。
reason = boot status = verify
5、升级开机完成后
升级过程中会筛选出近期用过的应用进行优化,而针对那些未被选中的,原生则是放到了开机完成后再进行优化,这也是考虑到全部都在开机过程中做,时间太长。 在R 上这一过程的应用是采取了speed-verify模式编译,与安装场景的级别相当,因此会占用较多的系统资源,该过程会在开机完成一分钟后进行。
在S上这一过程的应用是采取了extract模式,不涉及到编译。且谷歌已调整为开机十分钟后进行,相比之前的speed-verify,该模式不涉及到编译,只是单纯的解压,当前S 保留了该功能。 reason = boot status = extract
R上默认关闭,S上可以通过以下命令临时关闭。
adb shell cmd jobscheduler cancel android 801
在Android T上谷歌将其推迟到了idle状态执行,且灭屏充电编译时该优化必须执行完成,才能进行接下来的编译。谷歌计划在Android U上彻底删除该触发类型的编译。
三、如何在systrace中查看dex2oat编译类型
以高通骁龙原生相机为例,先在trace中找到对应的进程。
Trace中一般会有OpenDexFilesFromOat,点击后面的location可以查看到应用的编译模式和触发原因。

四执行dex2oat时打印的log
BackgroundDexOptService
installd
dex20at64


四、使用命令强制执行dex2oat
一、强制编译命令
如下:adb shell cmd package compile
1、基于profile文件强制编译某个应用:
adb shell cmd package compile -m speed-profile -f +package_name
2、强制全面speed编译某个应用:
adb shell cmd package compile -m speed -f +package_name
3、基于profile强制编译所有带profile文件的应用:
adb shell cmd package compile -m speed-profile -f -a
4、强制全面speed编译所有应用:
adb shell cmd package compile -m speed -f -a
二、清除配置文件数据并移除经过编译的代码
请运行以下命令:
1、针对某个应用:
adb shell cmd package compile --reset +package_name
2、针对所有应用:
adb shell cmd package compile --reset -a
相关文章:
dex2oat编译模式、触发场景、命令强制执行
dex2oat简单理解就是把delvik虚拟机的可执行文件dex转化成AndroidRuntime虚拟机的可执行文件oat。 Android T版本由PKMS下发命令、native层进程installd负责具体执行dex2oat操作。installd回去调用dex2oat64完成编译工作,可以将dex2oat64理解成一个程序。源码路径&…...
深度学习 | TCN时间卷积神经网络模型答疑
深度学习 | TCN时间卷积神经网络模型答疑 目录 深度学习 | TCN时间卷积神经网络模型答疑问题汇总问题回答参考资料问题汇总 1.使用 TCN 进行序列建模有哪些优势? 2.TCN 的特征? 问题回答 1.使用 TCN 进行序列建模具备以下优势: 并行性。与 RNN 中后继时间步长的预测必须等待…...
Linux之修改服务端口号
本次演示以SSH服务为例,SSH默认监听端口是22,先保留了22端口,所以我们要进入ssh的配置文件添加新端口并注释或删掉原有端口。 1、使用vi编辑器修改文件 sshd_config,路径是/etc/ssh/sshd_config,找到“#Port 22”,添加新的端口号10086。 2、如果你关闭了…...
LeetCode笔记:Weekly Contest 361
LeetCode笔记:Weekly Contest 361 0. 吐槽1. 题目一 1. 解题思路2. 代码实现 2. 题目二 1. 解题思路2. 代码实现 3. 题目三 1. 解题思路2. 代码实现 4. 题目四 1. 解题思路2. 代码实现 比赛链接:https://leetcode.com/contest/weekly-contest-361 0. …...
Springboot快速搭建Web API项目
内容概述 SpringBoot最常见得用途就是web api项目。 本文介绍使用自动配置功能,通过最简洁的pom依赖,快速搭建一个示例项目。 实现的功能为:接收http请求并返回json格式的数据。 一、配置pom.xml依赖 1.引入springweb依赖 <dependenc…...
数据结构day06(单向循环链表、双向链表)
双向链表的练习代码 head.h #ifndef __HEAD_H__ #define __HEAD_H__ #include <stdio.h> #include <stdlib.h> #include <string.h> typedef int database; typedef struct double_link_list{union{database data;int len;};struct double_link_list* pre;…...
zabbix -- 新建主机
目录 一、新建主机 二、新建监控项 IP主机192.168.136.55zabbix控制端/服务端192.168.136.56zabbix被控端/客户端 一、新建主机 主机参数 名称、群组(每台主机必须属于某个主机组内)、ip、端口 创建完成,如果你的ZBX为灰色,代…...
=>符号含义
>主要有两方面的作用,一个限制属性状态,另一个简化匿名委托和Lambda 用法一:定义只读属性 public class ManPeople { public string Sex > "男";public string Name { get; set; }}public class WomanPeople { publi…...
Docker+Jenkins(blueocean)+Gitee构建CICD流水线实战
一、配置JDK 1.1 编辑profile文件 vim /etc/profile export JAVA_HOME/home/jdk/jdk1.8.0_301 export JRE_HOME$JAVA_HOME/jre export CLASSPATH.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib export PATH$PATH:$JAVA_HOME/bin:$JRE_HOME/bin 1.2 使配置生效 source /etc/pro…...
Redis快速入门
文章目录 0. Redis介绍1. Centos下Redis安装2. redis.conf配置文件介绍3. redis相关命令4.redis中发布订阅和事务4.1 发布订阅(Pub/Sub)4.2 事务 5. redis封装系统服务6. 问题与解决6.1 启动Redis报错:Could not create Server TCP listening…...
EasyExcel 修改导出的文件属性
EasyExcel 修改导出的文件属性 导出的文件有多种属性,本文只针对sheet名称进行举例 需要自定义拦截器 ExcelWriter excelWriter EasyExcel.write(fileName).withTemplate(stream).registerWriteHandler(new TemplateSheetStrategyHandler()).build()registerWriteHandler (n…...
电子班牌云平台系统——智慧校园管理工具,多媒体信息发布、走班排课、家校互通、物联控制、教务管理、考勤管理、素质评价、日常办公
电子班牌云平台源码,saas模式微服务架构 电子班牌是一款智慧校园管理工具,也是校园多媒体展示平台。智慧班牌融合了多媒体信息发布、走班排课、家校互通、物联控制、教务管理、考勤管理、素质评价、日常办公等一系列应用,是校园管理的现代化手…...
docker-compose 部署 Seata整合nacos,Postgresql 为DB存储
docker-compose 部署 Seata整合nacos,Postgresql 为DB存储 环境 详情环境可参考 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 我这里 <spring.cloud.alibaba-version>2021.1</spring.cloud.alibaba-version>所…...
three.js 场景中如何彻底删除模型和性能优化
three.js 场景中如何彻底删除模型和性能优化 删除外部模型 在three.js场景中,要彻底删除外部模型,需要执行以下几个步骤: 从场景中移除模型 你可以使用 scene.remove(model) 或者 scene.remove(model.children[0]) 将模型从场景中移除。如果…...
Bridge Champ举办人机对战赛:NFT游戏与传统竞技共生发展编织新格局
概要 现在,NFT与体育竞技正日益紧密地联系在一起。一些体育项目开始推出与赛事或球队相关的NFT,同时也有部分NFT游戏开始举办电子竞技赛事。这种共生发展正在改变体育竞技的生态。 笔者采访了桥牌冠军项目相关负责人,探讨NFT游戏与传统体育竞技的融合潜力。桥牌冠军近期成功举…...
Visual Studio软件_MSC_VER值(MSVC编译器版本)的获取方法
本文介绍查看Visual Studio软件_MSC_VER值的方法。 _MSC_VER是微软公司推出的C/C 编译器——MSVC编译器的一个内置宏,其值表示当前Visual Studio软件中MSVC编译器的具体版本。不同的Visual Studio软件版本对应着不同的MSVC编译器版本——无论是不同发布年份的版本&…...
02-Linux-IO多路复用之select、poll和epoll详解
前言: 在linux系统中,实际上所有的 I/O 设备都被抽象为了文件这个概念,一切皆文件,磁盘、网络数据、终端,甚至进程间通信工具管道 pipe 等都被当做文件对待。 在了解多路复用 select、poll、epoll 实现之前ÿ…...
echo、print_r、print、var_dump 、die
die()和exit()函数都有终止线程的作用 是php断点调试需要使用的最主要的函数 die()函数一般与“or”一并使用,写作“or die()” var_dump()和print_r() var_dump() 显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值&#…...
【LeetCode75】第四十四题 省份数量
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们一个二维数组,表示城市之间的连通情况,连在一起的城市为一个省份,问我们一共有多少个省份。 这…...
把DTC从Excel导入cdd的方法
本文是基于CANdelaStudio12.0讲解 问题一:当导入DTC的xxx.cdi文件报如下红色错误 可能原因:在设置具有下拉框的属性的内容时,输入的内容不在下拉框列表中 解决办法:在.cddt文件中更新“”Error Code Table“”内容,把新的选项更新…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...
