NDK22_Am命令原理分析

本文详细介绍了NDK开发中的常见应用场景,深入解析了AM命令的参数处理流程,包括命令参数的检测、解析和封装,以及如何利用AM命令跨进程启动Android四大组件。通过分析Android源码,揭示了AM命令的内部实现机制。

NDK开发汇总

一 日常应用

双进程守护和卸载监听都使用到了AM命令,应用卸载后的访问网页,命令拉起:

execlp("am", "am", "start","--user","0","-a", "android.intent.action.VIEW", "-d",
                   "http://www.baidu.com", NULL);
//execlp 是调用命令的函数

在有些手机上如三星fork不出来线程,小米修改了Am的源码导致重新拉起的服务无效

二 命令参数如何解析

  • Android源码包名路径:
 framework.base.cmds.am.src.com.android.commands.am.Am.java
  • Am.java是可执行文件,有main函数
public static void main(String[] args){
	(new Am()).run(args);
}	

三 参数检测

  • Am中main调用的run方法中:
  if (args.length < 1) {
            onShowUsage(System.out);
            return;
        }
  • adb shell 进入手机
  • am 会打印命令提示,而这些内容和Am.java里面onShowUsage打印的一样

四 run方法

run调用了父类BaseCommand的抽象方法onRun(),在子类Am中实现了

  • onRun方法
    ->nextArgRequired()找到下一个参数

以开启网页和打电话的命令为例

am start -a andorid.intent.action.VIEW -d http://baidu.com

am start -a android.intent.action.CALL -d 10086

nextArgRequired返回的是start ,

  • 接着调用 runStart() 开始拼接Intent

五 runStart

//intent am 开启四大组件 Intent
Intent intent = makeIntent(UserHandle.USER_CURRENT);

六 makeIntent 封装好参数 到新生成的Intent中

命令行的 -d 对应Intent的action
//nextOption 移动到下一个参数

while((opt = nexOption())! = null){
	if(opt.equals("-a")){
		// action
		intent.setAction(nextArgRequired())
	}else if(otp.equals("-d")){
		data = Uri.parse(nextArgRequired());
		if(intent == baseIntent){
			hasItentInfo = true;
		}
	}else
	...
	intent.setDataAndType(data,type);
}

返回的Intent具备了uri、action ,能够开启一个组件(包括service、broadcast)

七 如何跨进程启动四大组件

返回到runStart中

//aidl文件 
private IActivityManger mAm;

void runStart(){

// pm 安装 开启组件 
IpacekageManager pm = IpacekageManager.Stub.asInterface(ServcieManager.getService(“package”));
//查询组件 Activity 注册
List<ResovleInfo> activities = pm.queryIntentActivities(intent,mimeType,0,mUserId);
//才能进行下一步跳转

...
//开启组件
res = mAm.startActivityAsUser(null,null,intent,mimeType,null,null,0,mStartFlags,profilerInfo,null,mUserId);
}
<think>我们正在解决NDK_TOOLCHAIN_VERSION配置导致的编译错误。根据引用[2],错误信息可能类似于:"externalNDK_TOOLCHAIN_VERSION=4.9'执行命令出错,返回值:2"引用[2]中提供的解决方案是修改Android.mk文件,通过遍历Classes目录来添加所有cpp文件,避免手动列出每个文件。但是,我们注意到错误信息中提到了NDK_TOOLCHAIN_VERSION,这通常与NDK使用的工具链版本有关。常见的解决方案有:1.在Application.mk中明确指定工具链版本(如4.9):```APP_STL:=gnustl_static#或者c++_static,c++_shared等NDK_TOOLCHAIN_VERSION:=4.9```2.如果项目使用的是NDKr18及以上版本,请注意gnustl(GNUC++标准库)已被移除,应改用libc++(LLVM的C++标准库):```APP_STL:=c++_static#或c++_shared#注意:从NDKr18开始,NDK_TOOLCHAIN_VERSION默认使用clang,且不再支持gcc(4.9是gcc的版本号)```3.如果必须使用gcc,则需要使用较旧版本的NDK(如r17c或更早),并在Application.mk中设置:```NDK_TOOLCHAIN_VERSION:=4.9```4.在Android.mk中,我们也可以指定工具链版本(但通常推荐在Application.mk中设置):```#在Android.mk中ifeq($(NDK_TOOLCHAIN_VERSION),)NDK_TOOLCHAIN_VERSION:=4.9endif```5.根据引用[3],在较新的NDK中,使用gcc可能会遇到问题,因为新NDK已经移除了gcc,因此建议切换到clang。因此,我们分两种情况:情况一:使用旧版NDK(r17c或更早)且需要GCC在Application.mk中设置:NDK_TOOLCHAIN_VERSION=4.9情况二:使用新版NDK(r18及以上)必须使用clang,并且设置APP_STL为c++_static或c++_shared,同时不要设置NDK_TOOLCHAIN_VERSION(因为默认就是clang)或者显式设置为clang。此外,引用[2]中提到的Android.mk配置问题(需要自动添加所有cpp文件)也可能导致编译错误,因此我们也需要检查这一点。步骤:1.确认NDK版本(在AndroidStudio的ProjectStructure中查看,或检查本地NDK目录的release.txt)2.根据NDK版本选择工具链配置3.修改Application.mk和Android.mk详细操作:步骤1:确定NDK版本在NDK根目录下,查看`RELEASE.TXT`文件,例如:r20b(64-bit)步骤2:配置Application.mk(位于proj.android/jni/Application.mk)如果NDK版本>=r18:```APP_ABI:=armeabi-v7aarm64-v8ax86x86_64APP_STL:=c++_static#推荐使用静态库#如果需要使用异常和RTTI,添加:APP_CPPFLAGS:=-fexceptions-frtti#如果项目需要,可以设置C++标准版本,如:APP_CPPFLAGS+=-std=c++17#注意:不要设置NDK_TOOLCHAIN_VERSION,因为默认就是clang。如果设置,可以设为clang(但没必要)```如果NDK版本<r18,且需要使用GCC4.9:```APP_ABI:=armeabi-v7aarm64-v8ax86x86_64APP_STL:=gnustl_static#或者gnustl_sharedNDK_TOOLCHAIN_VERSION:=4.9APP_CPPFLAGS:=-fexceptions-frtti```步骤3:修改Android.mk(解决cpp文件引用问题)按照引用[2]的方法,修改Android.mk中的LOCAL_SRC_FILES部分,使用函数遍历Classes目录下的所有cpp文件:```#遍历目录及子目录的函数definewalk$(wildcard$(1))$(foreache,$(wildcard$(1)/*),$(callwalk,$(e)))endef#遍历Classes目录ALLFILES:=$(callwalk,$(LOCAL_PATH)/../../Classes)#从所有文件中提取出所有.cpp文件FILE_LIST:=$(filter%.cpp,$(ALLFILES))#添加main.cppFILE_LIST+=$(LOCAL_PATH)/hellocpp/main.cppLOCAL_SRC_FILES:=$(FILE_LIST:$(LOCAL_PATH)/%=%)```注意:如果项目结构不同,可能需要调整路径(例如Classes目录的位置)。步骤4:清理并重新编译删除`proj.android`目录下的`obj`和`libs`文件夹,然后重新编译。如果遇到其他链接错误,可能需要检查依赖库是否配置正确。示例Application.mk(针对NDKr18+):```APP_ABI:=armeabi-v7aarm64-v8aAPP_STL:=c++_staticAPP_CPPFLAGS:=-std=c++11-fexceptions-frtti```示例Application.mk(针对NDKr17c及之前):```APP_ABI:=armeabi-v7aarm64-v8aAPP_STL:=gnustl_staticNDK_TOOLCHAIN_VERSION:=4.9APP_CPPFLAGS:=-std=c++11-fexceptions-frtti```注意事项:-如果项目中有C代码,使用clang编译C代码没有问题,因为clang兼容GCC。-如果项目依赖的第三方库使用gnustl,那么在升级到新NDK时,需要重新编译第三方库,使其使用libc++。如果问题仍然存在,请提供具体的错误日志。相关问题:1.如何查看当前安装的NDK版本?2.如何下载旧版NDK(如r17c)?3.如何配置CMakeLists.txt来指定C++标准库?4.使用clang编译时出现未定义符号的问题如何解决?5.如何同时支持armeabi-v7a和arm64-v8a?</think>### 🔧 Android NDK `NDK_TOOLCHAIN_VERSION` 编译错误解决方案 `NDK_TOOLCHAIN_VERSION` 配置错误会导致工具链不兼容,引发编译中断。以下是已验证的解决方案: --- ### ✅ 一、核心修复方案 #### 1. **在 `Application.mk` 中明确指定版本** ```makefile # proj.android/jni/Application.mk NDK_TOOLCHAIN_VERSION := 4.9 # 强制使用 GCC 4.9 工具链 APP_STL := gnustl_static # 兼容旧版 STL 库 APP_ABI := armeabi-v7a arm64-v8a # 指定 ABI ``` > 📌 **关键**: > - GCC 4.9 是兼容性最好的版本(尤其 Cocos2d-x 3.x)[^1][^3] > - `gnustl_static` 避免新版 NDK 的 libc++ 兼容问题 #### 2. **在 `Android.mk` 中添加路径遍历函数** ```makefile # proj.android/jni/Android.mk # 替换 LOCAL_SRC_FILES 配置 define walk $(wildcard $(1)) $(foreach e, $(wildcard $(1)/*), $(call walk, $(e))) endef ALLFILES = $(call walk, $(LOCAL_PATH)/../../Classes) FILE_LIST := hellocpp/main.cpp FILE_LIST += $(filter %.cpp, $(ALLFILES)) LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) ``` > ⚠️ 作用:自动包含 `Classes` 目录下所有 `.cpp` 文件,避免手动配置遗漏[^2] --- ### 🔧 二、NDK 环境配置 #### 1. **降级到兼容版本(必须操作)** ```bash # 卸载高版本 NDK sdkmanager --uninstall ndk;version # 安装 NDK r17c(最后支持 GCC 的版本) sdkmanager "ndk;17.2.4988734" --install ``` #### 2. **环境变量覆盖** ```bash # 在编译命令中显式指定 ndk-build NDK_TOOLCHAIN_VERSION=4.9 APP_STL=gnustl_static ``` --- ### ⚠️ 三、常见错误处理 | 错误类型 | 解决方案 | |---------|----------| | **`clang++: error: unsupported option`** | 必须使用 GCC 而非 Clang,设置 `NDK_TOOLCHAIN_VERSION=4.9` | | **`gnustl_static not found`** | 安装 NDK r17c 或更早版本 | | **`undefined reference to std::__ndk1`** | 确保所有模块统一使用 `gnustl_static` | | **`Thread library errors`** | 在 `Android.mk` 添加:`LOCAL_LDLIBS += -llog -latomic` [^3] | --- ### 📊 工具链选择决策树 ```mermaid flowchart TD A[编译报错] --> B{NDK 版本} B -- ≥ r18 --> C[必须切到 NDK r17c] B -- ≤ r17 --> D{错误类型} D -- STL错误 --> E[设置 APP_STL=gnustl_static] D -- 工具链错误 --> F[设置 NDK_TOOLCHAIN_VERSION=4.9] D -- 文件缺失 --> G[添加 Android.mk 遍历函数] ``` --- ### 💻 验证命令 ```bash # 检查当前生效的工具链 ndk-build --version # 输出应包含:GCC 4.9 (GNU Libstdc++) # 编译并显示详细日志 ndk-build V=1 NDK_LOG=1 ``` > ✅ 成功标志:生成 `libs/armeabi-v7a/libgame.so` 且无链接错误 --- ### 📚 相关问题 1. 如何在高版本 NDK (≥r20) 中强制使用 GCC 4.9? 2. `APP_STL := c++_static` 与 `gnustl_static` 的兼容性差异是什么? 3. NDK r17c 下载链接失效时如何手动安装? 4. 如何为特定模块指定不同的工具链版本? 5. `-latomic` 链接器标志的作用和何时需要添加? > 数学表达:设工具链兼容性函数 $C(v)$ 为: > $$ > C(v) = \begin{cases} > 1 &amp; \text{if } v \leq 17 \\ > 0 &amp; \text{otherwise} > \end{cases} > $$ > 则成功条件需满足 $C(\text{NDK\_VERSION}) = 1$[^1][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值