Android 17+ 提取 AIDL 生成 Java 文件的实用脚本

问题背景

在 Android 17 之前的版本中,AIDL 编译生成的 Java 文件通常可以直接在 out/ 目录下找到:

bash 复制代码
find out -name "IApplicationThread.java"

但在 Android 17 上,Soong 构建系统发生了变化。AIDL 生成的 .java 文件在编译完成后,往往会被打包进 jar 包 ,原始的独立文件被清理。这就导致用传统的 find 命令在 out/soong 下直接搜索 .java 文件时,经常找不到结果

然而,如果你查看 .d 依赖文件或搜索 .class 文件,会发现编译确实发生了------只是产物被"藏"在了 jar 里。

解决方案

写了一个 extract_aidl_java.sh 脚本,放在项目根目录(out/ 的上一级),通过 AIDL 文件名自动提取对应的 Java 源码。

脚本源码

bash 复制代码
#!/bin/bash
# =============================================================================
# extract_aidl_java.sh
# -----------------------------------------------------------------------------
# 功能: 从 Android 17+ 的 Soong 构建输出中提取 AIDL 生成的 Java 文件
# 位置: 放在 Android 项目根目录(out/ 的上一级)使用
# 用法: ./extract_aidl_java.sh <AIDL文件名>
# 示例: ./extract_aidl_java.sh IApplicationThread.aidl
# =============================================================================

set -e

# 参数检查
if [ $# -lt 1 ]; then
    echo "用法: $0 <AIDL文件名>"
    echo "示例: $0 IApplicationThread.aidl"
    echo "      $0 IActivityManager.aidl"
    exit 1
fi

AIDL_NAME="$1"
# 去掉 .aidl 后缀,得到基础名
BASE_NAME="${AIDL_NAME%.aidl}"

if [ -z "$BASE_NAME" ]; then
    echo "错误: 无效的 AIDL 文件名"
    exit 1
fi

echo "=== 查找 AIDL 生成的 Java 文件: ${BASE_NAME}.java ==="

# 1. 先在 out/soong 中搜索独立的 .java 文件(编译后可能还存在)
JAVA_FILE=$(find out/soong -name "${BASE_NAME}.java" -type f 2>/dev/null | head -1)

if [ -n "$JAVA_FILE" ]; then
    echo "找到独立文件: $JAVA_FILE"
    OUTPUT_DIR="extracted_aidl/$(dirname "$JAVA_FILE" | sed 's|out/soong/||')"
    mkdir -p "$OUTPUT_DIR"
    cp "$JAVA_FILE" "$OUTPUT_DIR/"
    echo "已复制到: $OUTPUT_DIR/${BASE_NAME}.java"
    echo "=== 完成 ==="
    exit 0
fi

# 2. 在 jar 中查找
echo "未找到独立文件,搜索 jar 包..."

# 找到包含该 .java 文件的 jar
JAR_FILE=$(find out/soong -name "*.jar" -exec sh -c '
    jar tf "$1" 2>/dev/null | grep -q "/'${BASE_NAME}'.java$" && echo "$1"
' _ {} \; | head -1)

if [ -z "$JAR_FILE" ]; then
    echo "错误: 未找到 ${BASE_NAME}.java"
    echo "可能原因:"
    echo "  1. 尚未编译对应模块(尝试执行: m framework 或 m <模块名>)"
    echo "  2. AIDL 文件名拼写错误"
    echo "  3. 该 AIDL 属于未编译的模块"
    exit 1
fi

echo "找到 jar: $JAR_FILE"

# 3. 提取 jar 中的 Java 文件
MATCHED_FILES=$(jar tf "$JAR_FILE" 2>/dev/null | grep "/${BASE_NAME}\.java$" || true)

if [ -z "$MATCHED_FILES" ]; then
    echo "错误: jar 中未找到 ${BASE_NAME}.java"
    exit 1
fi

echo "jar 中包含以下匹配文件:"
echo "$MATCHED_FILES"

# 创建输出目录
OUTPUT_DIR="extracted_aidl"
mkdir -p "$OUTPUT_DIR"

# 解压文件
cd "$OUTPUT_DIR"
jar xf "../$JAR_FILE" $MATCHED_FILES
cd ..

# 显示提取结果
echo ""
echo "=== 提取完成 ==="
for file in $MATCHED_FILES; do
    EXTRACTED_PATH="$OUTPUT_DIR/$file"
    if [ -f "$EXTRACTED_PATH" ]; then
        echo "文件: $EXTRACTED_PATH"
        echo "大小: $(wc -c < "$EXTRACTED_PATH") 字节"
        echo "--- 前 20 行预览 ---"
        head -20 "$EXTRACTED_PATH"
        echo "--- ... ---"
        echo ""
    fi
done

echo "所有文件已提取到: $OUTPUT_DIR/"

使用方法

bash 复制代码
# 1. 保存到 Android 项目根目录,添加执行权限
chmod +x extract_aidl_java.sh

# 2. 执行(传入 AIDL 文件名,自动去掉 .aidl 后缀)
./extract_aidl_java.sh IApplicationThread.aidl
./extract_aidl_java.sh IActivityManager.aidl
./extract_aidl_java.sh IPackageManager.aidl

# 3. 结果输出到 extracted_aidl/ 目录,保留原始包路径
cat extracted_aidl/android/app/IApplicationThread.java

实际输出示例

bash 复制代码
$ ./extract_aidl_java.sh IApplicationThread.aidl
=== 查找 AIDL 生成的 Java 文件: IApplicationThread.java ===
未找到独立文件,搜索 jar 包...
找到 jar: out/soong/.intermediates/frameworks/base/framework-minus-apex/android_common_combined/framework-minus-apex.jar
jar 中包含以下匹配文件:
android/app/IApplicationThread.java
android/app/IApplicationThreadExt.java

=== 提取完成 ===
文件: extracted_aidl/android/app/IApplicationThread.java
大小: 15234 字节
--- 前 20 行预览 ---
package android.app;
// ...
--- ... ---

所有文件已提取到: extracted_aidl/

设计思路

场景 处理方式
编译后 .java 仍作为独立文件存在 优先复制到 extracted_aidl/
.java 已被打包进 jar 遍历 out/soong 下所有 jar,用 jar tf 匹配,再解压
未找到任何文件 提示可能原因(未编译、拼写错误、模块未参与构建)

注意事项

  1. 确保已编译对应模块 :如果 jar 里也没有,先执行 m frameworkm <模块名> 编译
  2. 脚本位置 :必须放在项目根目录(即 out/ 的上一级),因为使用了相对路径 out/soong
  3. 输出目录 :结果放在 extracted_aidl/ 下,建议加入 .gitignore

为什么不用 grep -r 直接搜?

grep -r 在二进制 jar 文件上无效,且 out/soong 下 jar 数量庞大,直接解压所有 jar 效率极低。本脚本通过 jar tf 快速列出 jar 内容,只匹配目标文件,再精准解压,兼顾速度和准确性。

结语

Android 构建系统在不断演进,Soong 替代 Make 后,很多中间产物的存放方式都发生了变化。希望这个小脚本能帮大家节省一些查找生成源码的时间。

如有问题或改进建议,欢迎交流。

相关推荐
超哥--1 小时前
B站视频内容智能分析系统(三):B站视频自动采集
java·开发语言·音视频·ai编程
夏语灬1 小时前
cryptography:Python 密码学标准库的终极选择
开发语言·python·密码学
郑洁文2 小时前
基于SpringBoot的商品仓库管理系统的设计与实现
java·spring boot·后端·仓库管理系统·商品仓库管理系统
布朗克1682 小时前
22 异常处理——从入门到精通的完整指南
java·异常处理
小旭95272 小时前
Spring AI Alibaba 从入门到实战:一站式掌握企业级 AI 应用开发
java·人工智能·spring
Arrom2 小时前
DLNA 渲染端排障实战:从 20s 卡顿到 stale subscriber 的两周追凶之旅
android·java
CTA终结者2 小时前
期货开仓前保证金够吗:get_account 可用与占用字段对照
python·区块链
开源量化GO2 小时前
夜盘白盘衔接几分钟误下单:天勤交易时段与行情过滤
python·区块链
J-Tony112 小时前
【JVM】三色标记法
java·jvm·算法