framework&framework-minus-apex&android.jar的区别

编译 framework.jar(frameworks/base boot framework)

bash 复制代码
# 进入 AOSP 根目录,先 envsetup + lunch(不 lunch 会报错)
cd /home/maqi/android13-r44
source build/envsetup.sh
lunch sdk_car_x86_64-userdebug

# 编译整个 boot framework(make 和 m 等价,m 就是 make 的封装)
make framework -j12
# 或
m framework -j12

产出位置:

  • 原始 classes.jar:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar(~38M,25879 个类)
  • 装进系统的 bootclasspath jar:out/target/product/emulator_car_x86_64/system/framework/framework.jar(~36M,含 dex)

注意:framework.jar 是系统开机就加载的基础框架(含大量 @hide 私有 API),不是给 app 集成用的 jar。app 编译用 SDK 的 android.jar(公开接口桩),不要 implementation 整个 framework.jar,会跟系统已加载的那份类重复直接崩。


framework 与 framework-minus-apex 的区别(frameworks/base/Android.bp L340~393)

模块 装设备? 内容 用途
framework-minus-apex 是(stem: "framework" 装成 framework.jar) framework 减掉 APEX 模块(wifi/tethering/permission/media 等)的类 设备上真正跑的那个框架
framework 否(installable: false) minus-apex + framework-updatable-stubs-module_libs_api + 注解 纯编译用,给内置 app 当完整 API 类路径
  • minus-apex 名字由来:Android 10 起把一批类从 framework 拆成可独立升级的 Mainline APEX 模块,minus-apex = 减掉这些。
  • make framework → framework_intermediates/classes.jar(38M);make framework-minus-apex → framework-minus-apex_intermediates/classes.jar(37M)。
  • 两个都是 3 万多类的大 jar,本质都是「系统框架」档,不是给第三方 app 打进 apk 用的。

app 引用 framework 隐藏 API 的两种做法(编译期)

目标:让 app 在编译期能引用 @hide / @SystemApi 隐藏 API。区别 = 改哪一层。

做法 A:替换 SDK 下的 android.jar(全局,改 SDK 层)

bash 复制代码
# full jar(含 @hide)来源:
# out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
# 覆盖到 SDK 的 android.jar(路径按 compileSdk 版本,如 android-33)
cp out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar \
   "$ANDROID_SDK/platforms/android-33/android.jar"

做法 B:compileOnly framework.jar(局部,改 Gradle 单模块层)

gradle 复制代码
// app/build.gradle
dependencies {
    compileOnly files('libs/framework.jar')   // 只编译、不打进 apk
} 

framework 相关 jar 横向对比表

对比项 编译路径/来源 编译方法 产物路径 作用 使用方法(app 侧)
framework.jar frameworks/base/Android.bp,name:"framework" make framework -j12 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar(38M) build-only 合成 jar(minus-apex + 可更新模块 API 桩),给内置 app 完整 API 不装设备;可当做法 A/B 的完整桩来源
framework-minus-apex frameworks/base/Android.bp,name:"framework-minus-apex" make framework-minus-apex -j12 framework-minus-apex_intermediates/classes.jar(37M)→ stem:"framework" 装成 out/target/product/<target>/system/framework/framework.jar(36M) 设备上真正运行的框架(去掉 APEX 模块的类) 随系统镜像烧录,bootclasspath 加载,不碰 app
android.jar(public) SDK 快照 prebuilts/sdk/current/public/android.jar;源码树里由 android_stubs_current 从 framework 源码抽桩生成 平时 app 开发不编译(用 check-in 快照);改公开 API 后需 make update-api + 重编才更新 prebuilts/sdk/current/public/android.jar(快照)/ out/.../android_stubs_current_intermediates/classes.jar(构建产物) 公开 API 桩(方法体是 Stub) compileSdk 33 自动引用,什么都不用做
android.jar(system) prebuilts/sdk/current/system/android.jar 无需编译 同上 system/ 目录 @SystemApi 桩 系统/特权 app(Soong 里 sdk_version:"system_current" 对应它)
做法 A:替换 android.jar 用 framework_intermediates/classes.jar make framework 后 cp 覆盖 覆盖 $ANDROID_SDK/platforms/android-33/android.jar 全局(整个 SDK)暴露 @hide/@SystemApi 覆盖后正常写代码即可
做法 B:compileOnly framework.jar framework_intermediates/classes.jar 拷成 app/libs/framework.jar make framework 后 cp 到 libs/ app/libs/framework.jar 单模块暴露隐藏 API(仅能补「整类被藏」) dependencies { compileOnly files('libs/framework.jar') }

android.jar 是什么:

一句话:android.jar 是 app「编译时」用的 API 桩(stub),只有公开接口的签名,没有真实实

现。

你这棵树上 prebuilts/sdk/current/ 下就有 6 个 android.jar,按「谁能用」分层:

  • public/android.jar ------ 公开 API,所有 app 都能用(就是 Gradle compileSdk 33
    对应那个)
  • system/android.jar ------ @SystemApi,系统/特权 app 才能用
  • test/android.jar ------ @TestApi,测试用
  • module-lib/android.jar ------ Mainline 模块用
  • system-server/android.jar ------ system_server 用
  • core/android.jar ------ core platform

SDK 里则是 platforms/android-33/android.jar(对应 prebuilts/sdk/current/public/andro

id.jar)。

update-api 具体操作(改了公开 API 后)

改了公开 API(新增/删除/改 public 方法或类)后编译,会报:

复制代码
You have tried to change the API from what has been previously approved.

错误信息里会直接打印要执行的命令(m <模块名>-update-current-api),照抄即可。

两个选择(错误里写明的):

  1. 给新方法加 @hide(保持私有,不改公共 API)
  2. 跑 m <模块名>-update-current-api 更新签名文件

frameworks/base 主框架公开 API 的命令(模块名 api-stubs-docs-non-updatable):

bash 复制代码
m api-stubs-docs-non-updatable-update-current-api

它做的事:把新生成的签名覆盖回 checked-in 签名文件:

  • frameworks/base/core/api/current.txt(公开 API)
  • frameworks/base/core/api/removed.txt(删除的 API)

@SystemApi 同理(对应 core/api/system-current.txt):

bash 复制代码
m api-stubs-docs-non-updatable-system-update-current-api

旧叫法 make update-api 是 Android 10 之前;A13 用 m <模块>-update-current-api。更新后 current.txt 要过 review 才能提主干(Google 管控),自己本地刷机无所谓,直接跑。

疑问

你提到的 update-api 和 stub 产物,核心作用是维护 Android 系统的 API 契约(Contract)与兼容性防线,而非直接用于 App 开发。

简单来说:

  • framework.jar (全量):是**"原材料"**,包含所有代码(公开 + 隐藏),用于系统运行或你手动替换 SDK 来"作弊"编译。
  • android.jar (Stub):是**"官方考纲"**,只包含允许公开的 API,用于约束普通 App 只能调用规定接口。
  • update-api:是**"修订考纲的工具"**,当系统开发者新增了公开 API 时,必须运行此命令更新"考纲",否则编译会报错。

以下是详细的用途解析与对比:

1. 核心概念辨析:为什么需要这么多产物?

产物/命令 本质定义 核心用途 谁在用? 为什么不能混用?
framework.jar (全量实现) 系统真实代码 。包含 public, @hide, @SystemApi 所有类和方法的真实逻辑 。 系统运行。手机开机加载到 BootClassPath;或作为 AOSP 内置 App 的编译依赖 。 系统本身、内置 App、想破解隐藏 API 的开发者。 若普通 App 直接依赖它,会因包含大量非公开 API 而破坏谷歌的兼容性承诺,且体积过大。
android.jar (Public Stub) 公开 API 桩 。仅含 public 接口签名,方法体为 throw new Stub() 。 编译约束 。确保第三方 App 只能 调用谷歌承诺稳定的公开接口,防止滥用内部 API 。 普通第三方 App 开发者 (Gradle 默认引用)。 它是"过滤器"。如果直接用 framework.jar 替代,就失去了"禁止调用隐藏 API"的编译期检查机制。
update-api (构建命令) 签名同步工具 。将编译生成的最新 API 签名,覆盖回源码树中的 .txt 记录文件 。 API 管理 。当系统开发者新增/修改了 public 方法后,必须运行此命令更新"考纲",否则 CI 编译会报错 。 AOSP 系统开发者 (Framework 团队)。 普通 App 开发者无需运行。这是系统源码维护流程的一部分,用于保证 API 演进的可追溯性。

2. update-api 的具体工作流与意义

当你修改了 AOSP 源码中的 Java 文件(例如在 Activity.java 中新增了一个 public void myNewMethod()),编译系统会检测到当前的 API 签名记录(current.txt)与实际代码不符。

为什么会报错?

Android 有一套严格的 API Check 机制。编译时会比对:

  1. 实际代码 :当前源码中所有的 public 接口。
  2. 记录文件 :frameworks/base/core/api/current.txt(即"考纲")。
    如果两者不一致,构建系统会抛出 You have tried to change the API from what has been previously approved 错误,阻止编译 。
update-api 做了什么?

运行该命令(如 m api-stubs-docs-non-updatable-update-current-api)后,系统会执行以下操作:

  1. 提取签名 :从最新编译的 Stub 中提取所有 public 类和方法的签名。
  2. 覆盖记录 :将提取出的签名写入 current.txt 和 removed.txt 文件 。
  3. 通过检查:下次编译时,实际代码与新的记录文件一致,报错消失。
bash 复制代码
# 典型操作场景:系统开发者新增了公开 API
# 1. 修改源码 frameworks/base/core/java/android/app/Activity.java (新增 public 方法)

# 2. 尝试编译,通常会报错提示 API 变更
m framework -j12 
# Error: You have tried to change the API from what has been previously approved.

# 3. 运行 update-api 命令 (根据错误提示的具体模块名)
# 这将更新 frameworks/base/core/api/current.txt
m api-stubs-docs-non-updatable-update-current-api

# 4. 重新编译,此时通过
m framework -j12

意义 :这确保了 Android 版本的 API 变更是有迹可循的。Google 在合入代码时,会审查 current.txt 的变动,防止意外暴露内部接口或误删旧接口 。

3. 三种 Jar 包的层级关系

  • Full (framework.jar):源头,什么都有。
  • Stub (android.jar):经过过滤的"子集",只给外人看。
  • Txt (current.txt):对"子集"的文字记录,用于版本控制。
  • update-api:当源头变了,用来同步更新"文字记录"的工具。

4. 对你的开发意味着什么?

  • 如果你是普通 App 开发者:

    • 不需要关心 update-api:那是 Google 和系统ROM开发者做的事。
    • 不需要关心 Stub 生成 :你只需要知道 android.jar 是限制你的"墙"。
    • 只需关注 framework.jar :如果你想翻墙(调用隐藏 API),你就拿 framework.jar 的编译产物去替换 android.jar,或者在 Gradle 里依赖它。这正是你之前操作的本质------用"全量原材料"替换了"过滤后的考纲" 。
  • 如果你是 ROM 定制/系统开发者:

    • 每当你修改了 Framework 层的 public 接口,必须运行 update-api,否则无法构建系统镜像。
    • 你需要理解 framework-minus-apex 和 framework 的区别,以便正确打包系统分区 。

总结

搞那么多产物是为了分工:

  1. framework.jar 负责跑(系统运行时用)。
  2. android.jar 负责管(编译期约束 App 行为)。
  3. update-api 负责记(维护 API 演进的档案)。

你之前的操作(替换 android.jar),实际上是绕过了"管"的环节,直接让编译器看到了"跑"的内容,从而实现了调用隐藏 API 的目的。

相关推荐
lee_curry1 小时前
第十周完整学习笔记:继续升级为“检索更准、权限安全、索引可维护、失败可恢复、长期可运行”的企业级 RAG 系统
python·ai·langchain·agent·langgraph
技术风向解码者1 小时前
安卓跨端选型:为什么优先看 Kuikly
android
科小怪1 小时前
大肥鱼桌宠下载(2026最新版):在安卓桌面上养一条会走会弹会碎碎念的胖鱼
android
qq3621967051 小时前
安卓安装包完整性校验:怎么确认下载的 APK 没被动过手脚
android
FLJwu2 小时前
《运动相机硬件防护选型实战》专栏|第二篇(PPTC 自恢复保险丝)
android·经验分享·数码相机·1024程序员节·运动相机
Ivanqhz2 小时前
MoE + LLM 应用
数据库·人工智能·pytorch·python·深度学习·算法·1024程序员节
Mr. zhihao2 小时前
Deep Agent 架构深度解析:主Agent与子Agent完整交互机制与核心参数作用
python·ai·langgraph·deepagent
狗凯之家源码网2 小时前
iOS C2 V2 与 Python FastAPI 全链路远控系统深度评测
python·ios·fastapi
超级架构师2 小时前
让 Fortran 模型自己调用 Agent:原生 Fortran 2008 实现深度剖析
人工智能·python·架构·机器人·开源·fortran