四大组件原理分析
# 05.四大组件原理分析
# 目录介绍
- 01.四大组件概述
- 1.1 四大组件的设计思想
- 1.2 组件注册与发现机制
- 1.3 组件间通信的本质
- 02.Activity原理深入分析
- 2.1 Activity的创建流程
- 2.2 生命周期的驱动机制
- 2.3 onSaveInstanceState与恢复
- 2.4 Activity的窗口关联
- 03.Activity启动模式源码分析
- 3.1 四种启动模式的实现
- 3.2 Intent Flags对Task的影响
- 3.3 taskAffinity的作用原理
- 3.4 多实例与SingleInstance的区别
- 04.Service原理深入分析
- 4.1 startService与bindService对比
- 4.2 Service的生命周期状态机
- 4.3 IntentService的设计原理
- 4.4 JobIntentService与WorkManager
- 05.BroadcastReceiver原理深入分析
- 5.1 静态注册与动态注册对比
- 5.2 广播分发的线程模型
- 5.3 LocalBroadcast的实现原理
- 5.4 有序广播的中止与修改
- 06.ContentProvider原理深入分析
- 6.1 Provider的跨进程通信机制
- 6.2 Cursor的数据传输原理
- 6.3 ContentObserver通知机制
- 6.4 FileProvider的实现原理
- 07.组件间通信机制
- 7.1 Intent的数据传递原理
- 7.2 Bundle的序列化机制
- 7.3 Binder传输大小限制
- 7.4 大数据传输方案
- 08.组件的进程间交互
- 8.1 跨进程启动组件的流程
- 8.2 远程Service的Binder通信
- 8.3 ContentProvider的跨进程查询
- 8.4 PendingIntent的延迟执行
- 09.组件安全与权限控制
- 9.1 组件的exported属性
- 9.2 Permission保护组件
- 9.3 签名级权限的应用
- 9.4 Android 12的安全增强
- 10.总结与面试要点
- 10.1 四大组件对比总结
- 10.2 高频面试题解析
- 10.3 最佳实践建议
# 01.四大组件概述
# 1.1 四大组件的设计思想
Android的四大组件(Activity、Service、BroadcastReceiver、ContentProvider)是应用开发的基石。它们的设计遵循了一个核心思想:组件化与松耦合。
四大组件的设计定位:
┌──────────────────────────────────────────────────────┐
│ Activity → 用户界面交互的载体,一个屏幕就是一个Activity │
│ Service → 后台长时间运行的任务,无界面 │
│ Broadcast → 系统级的事件通知与订阅机制 │
│ Provider → 跨进程的结构化数据共享 │
└──────────────────────────────────────────────────────┘
设计核心原则:
1.声明式注册:组件在Manifest中声明,系统统一管理
2.生命周期托管:组件的创建和销毁由系统控制,不是应用自己
3.Intent驱动:组件间通过Intent通信,实现松耦合
4.跨进程透明:调用者不需要关心目标组件在哪个进程
2
3
4
5
6
7
8
9
10
11
12
13
这种设计使得Android应用可以被灵活组合——一个应用可以启动另一个应用的Activity、绑定其Service、接收其广播、查询其数据,而不需要了解对方的实现细节。
# 1.2 组件注册与发现机制
所有组件都需要在AndroidManifest.xml中声明(动态注册的BroadcastReceiver除外),PMS在系统启动时扫描所有APK并解析Manifest,建立全局的组件注册表。
组件注册与发现流程:
开发者在Manifest中声明组件
→ PMS启动时解析所有APK的Manifest
→ 组件信息存入ComponentResolver
→ 运行时通过Intent查找:
显式Intent → 直接查ComponentName
隐式Intent → IntentFilter匹配
2
3
4
5
6
7
# 1.3 组件间通信的本质
四大组件间的通信本质上都是通过Binder IPC完成的。即使是同一个进程内的组件通信,也要经过AMS:
组件通信的Binder链路:
应用A进程 SystemServer 应用B进程
startActivity() ──→ AMS.startActivity() ──→ scheduleLaunchActivity()
startService() ──→ AMS.startService() ──→ scheduleCreateService()
sendBroadcast() ──→ AMS.broadcastIntent()──→ scheduleRegisteredReceiver()
query() ──→ AMS.getProvider() ──→ Provider.query()(直接Binder)
2
3
4
5
6
# 02.Activity原理深入分析
# 2.1 Activity的创建流程
当AMS决定启动一个Activity后,通过Binder通知目标进程创建Activity实例:
// AMS侧发起
// Android 9+通过ClientTransaction机制
ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(intent, ...));
clientTransaction.setLifecycleStateRequest(ResumeActivityItem.obtain(isForward));
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
// 应用端处理
// TransactionExecutor.execute()
// → LaunchActivityItem.execute()
// → ActivityThread.handleLaunchActivity()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 1.通过Instrumentation反射创建Activity实例
Activity activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
// 2.创建Context(ContextImpl)
ContextImpl appContext = createBaseContextForActivity(r);
// 3.调用Activity.attach()(关联Window、设置WindowManager)
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent, ...);
// 4.调用onCreate
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
return activity;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Activity创建的关键步骤:
1. Instrumentation.newActivity() → 反射创建Activity实例
2. Activity.attach() → 创建PhoneWindow、设置WindowManager
3. onCreate() → 开发者设置ContentView
4. onStart() → Activity可见
5. onResume() → Activity可交互
→ WindowManager.addView() → WMS创建窗口
2
3
4
5
6
7
# 2.2 生命周期的驱动机制
Activity的生命周期完全由AMS(ATMS)驱动。AMS通过Binder通知应用端执行对应的生命周期回调:
Android 9+的生命周期驱动机制(ClientTransaction):
AMS侧:
创建ClientTransaction
→ 添加LifecycleStateRequest(目标状态)
→ 通过IApplicationThread发送到应用端
应用端:
TransactionExecutor.execute()
→ cycleToPath():计算当前状态到目标状态的路径
→ 逐个执行路径上的每个生命周期回调
示例:从RESUMED到STOPPED
路径:RESUMED → PAUSED → STOPPED
执行:handlePauseActivity() → handleStopActivity()
示例:从STOPPED到RESUMED
路径:STOPPED → STARTED → RESUMED
执行:handleStartActivity() → handleResumeActivity()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2.3 onSaveInstanceState与恢复
状态保存时机:
- Activity被系统回收前(而非用户主动关闭)
- 具体触发点:onStop之前(Android P+在onStop之后)
- 场景:旋转屏幕、按Home键、内存不足被回收
保存流程:
AMS通知scheduleStopActivity(saveState=true)
→ handleStopActivity()
→ performSaveInstanceState()
→ onSaveInstanceState(outState)
→ Window.saveHierarchyState() ← View树的状态自动保存
→ 将Bundle通过Binder传给AMS保存在ActivityRecord中
恢复流程:
AMS启动Activity时将savedInstanceState传给应用端
→ performLaunchActivity()
→ onCreate(savedInstanceState) ← 开发者手动恢复
→ onRestoreInstanceState(savedInstanceState) ← 系统自动恢复View树
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.4 Activity的窗口关联
每个Activity关联一个Window(PhoneWindow),Window负责管理DecorView和视图层次:
Activity与Window的关系:
Activity
├── mWindow: PhoneWindow
│ ├── mDecor: DecorView(根View)
│ │ ├── StatusBar区域
│ │ ├── ContentView(setContentView设置的布局)
│ │ └── NavigationBar区域
│ └── mWindowManager: WindowManagerImpl
│ └── mGlobal: WindowManagerGlobal(进程级单例)
│ └── addView() → 通过Binder通知WMS创建WindowState
└── mToken: IBinder(AMS分配的Activity令牌)
2
3
4
5
6
7
8
9
10
11
# 03.Activity启动模式源码分析
# 3.1 四种启动模式的实现
四种启动模式在源码中的处理(ActivityStarter.java):
standard(LAUNCH_MULTIPLE):
computeLaunchingTaskFlags() → 使用调用者的Task
每次创建新的ActivityRecord
singleTop(LAUNCH_SINGLE_TOP):
deliverNewIntentLocked()中检查:
if (top == r && top.realActivity.equals(r.realActivity)) {
// 栈顶已有相同Activity → 调用onNewIntent,不创建新实例
deliverNewIntentLocked(top, r.intent);
} else {
// 正常创建
}
singleTask(LAUNCH_SINGLE_TASK):
getReusableIntentActivity()中查找:
遍历所有Task,找taskAffinity匹配的Task中的目标Activity
找到 → moveTaskToFront + clearTaskAbove + onNewIntent
没找到 → 创建新Task或在匹配affinity的Task中创建
singleInstance(LAUNCH_SINGLE_INSTANCE):
强制创建新Task,且该Task只能有这一个Activity
后续启动 → 复用已有实例 + onNewIntent
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 3.2 Intent Flags对Task的影响
常用Intent Flags及其在AMS中的处理:
FLAG_ACTIVITY_NEW_TASK:
→ 在新Task中启动(或匹配affinity的已有Task)
→ 从非Activity Context启动Activity时必须设置
FLAG_ACTIVITY_CLEAR_TOP:
→ 如果目标Activity已在Task栈中,清除其上方所有Activity
→ 配合singleTask效果:清除后调onNewIntent
FLAG_ACTIVITY_SINGLE_TOP:
→ 效果同singleTop启动模式(仅对栈顶生效)
FLAG_ACTIVITY_CLEAR_TASK:
→ 清除整个Task栈,目标Activity作为Task的根Activity
→ 必须配合FLAG_ACTIVITY_NEW_TASK使用
FLAG_ACTIVITY_NO_HISTORY:
→ Activity不会留在Task栈中
→ 离开后立即finish(不会出现在最近任务中)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 3.3 taskAffinity的作用原理
taskAffinity决定了Activity更倾向于归属哪个Task。默认值为应用包名,所有Activity属于同一个Task。
taskAffinity的使用场景:
1. singleTask/singleInstance启动模式 → 按affinity查找已有Task
2. FLAG_ACTIVITY_NEW_TASK → 在匹配affinity的Task中启动
3. allowTaskReparenting=true → Activity可以从启动它的Task迁移到affinity匹配的Task
示例:
App-A的ActivityX(affinity="com.a")启动App-B的ActivityY(affinity="com.b")
→ ActivityY在App-A的Task中运行
→ 用户按Home,再启动App-B
→ 如果allowTaskReparenting=true,ActivityY会迁移到App-B的Task中
2
3
4
5
6
7
8
9
10
# 3.4 多实例与SingleInstance的区别
singleTask vs singleInstance:
singleTask:
- 在匹配affinity的Task中保持单实例
- 该Task中可以有其他Activity在它上面
- ActivityA(singleTask) → startActivity(B) → B在同一Task中
singleInstance:
- 独占一个Task,Task中只有它自己
- ActivityA(singleInstance) → startActivity(B) → B必须在另一个Task中
- 最严格的单实例模式
2
3
4
5
6
7
8
9
10
11
# 04.Service原理深入分析
# 4.1 startService与bindService对比
两种启动方式的核心区别:
startService:
→ 生命周期:onCreate → onStartCommand → (运行中) → onDestroy
→ 特点:Service与启动者无生命周期关联
→ 停止:必须显式调用stopService/stopSelf
→ 适用:后台任务,不需要与调用者交互
bindService:
→ 生命周期:onCreate → onBind → (连接中) → onUnbind → onDestroy
→ 特点:Service与绑定者生命周期关联
→ 停止:所有绑定者unbind后自动销毁
→ 适用:需要与Service交互、获取返回数据
两者可以混合使用:
startService + bindService
→ 必须同时stopService + 所有unbind后才会销毁
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4.2 Service的生命周期状态机
// ActiveServices中Service的状态管理
// Service的核心状态由ServiceRecord中的字段组合表示:
// startRequested: 是否通过startService启动
// bindings.size() > 0: 是否有绑定连接
// isForeground: 是否是前台Service
// executingStart: 是否有onStartCommand在执行
// 生命周期状态转换:
// 首次startService:
// bringUpServiceLocked → realStartServiceLocked
// → scheduleCreateService(onCreate)
// → sendServiceArgsLocked(onStartCommand)
// 首次bindService:
// bringUpServiceLocked → realStartServiceLocked
// → scheduleCreateService(onCreate)
// → requestServiceBindingLocked → scheduleBindService(onBind)
// stopService:
// stopServiceLocked → bringDownServiceIfNeededLocked
// → bringDownServiceLocked
// → scheduleStopService(onDestroy)
// (需确保没有绑定连接)
// unbindService:
// unbindServiceLocked → removeConnectionLocked
// → 如果是最后一个连接且未被startService
// → bringDownServiceLocked(onDestroy)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 4.3 IntentService的设计原理
IntentService(已废弃,但设计思想值得学习)通过Handler+Looper+HandlerThread实现单线程串行处理:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) { super(looper); }
@Override
public void handleMessage(Message msg) {
// 在工作线程中执行
onHandleIntent((Intent) msg.obj);
// 执行完自动stopSelf
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
// 创建工作线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 将Intent封装为Message发送到工作线程
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 4.4 JobIntentService与WorkManager
IntentService的替代方案演进:
IntentService(已废弃)
→ JobIntentService(过渡方案,也已废弃)
→ WorkManager(推荐方案)
WorkManager的优势:
1.兼容性:自动选择JobScheduler/AlarmManager/Firebase JobDispatcher
2.约束条件:网络、电量、存储空间等约束
3.链式任务:支持任务的依赖和串行/并行组合
4.持久性:任务信息持久化到Room数据库,重启后恢复
5.遵守系统限制:自动适配Doze模式和后台限制
2
3
4
5
6
7
8
9
10
11
# 05.BroadcastReceiver原理深入分析
# 5.1 静态注册与动态注册对比
静态注册(Manifest声明):
注册时机:PMS扫描APK时解析Manifest
存储位置:PMS的ComponentResolver中
生命周期:只要应用安装就存在
限制:Android 8.0+大部分隐式广播不再触发静态接收者
进程:广播到达时系统会启动应用进程
动态注册(代码注册):
注册时机:调用registerReceiver时
存储位置:AMS的mReceiverResolver中
生命周期:与注册者生命周期绑定,需手动unregister
限制:无隐式广播限制
进程:必须进程存活才能接收
2
3
4
5
6
7
8
9
10
11
12
13
# 5.2 广播分发的线程模型
广播分发的线程处理:
AMS侧:
BroadcastQueue在AMS的Handler线程中分发
→ 通过Binder通知目标进程
应用端:
默认在主线程接收(onReceive在主线程执行)
→ 因此onReceive中不能做耗时操作(10秒ANR限制)
goAsync()机制(API 11+):
BroadcastReceiver.PendingResult result = goAsync();
// 在子线程中处理
new Thread(() -> {
// 耗时操作
result.finish(); // 必须调用finish
}).start();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 5.3 LocalBroadcast的实现原理
LocalBroadcastManager(已废弃)是进程内广播,不走AMS,直接在应用进程内完成匹配和分发:
// LocalBroadcastManager内部实现
// 本质是一个简单的Observer模式 + Handler
class LocalBroadcastManager {
// 注册表:Action → ReceiverRecord列表
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
// 用于在主线程分发的Handler
private final Handler mHandler;
public void sendBroadcast(Intent intent) {
// 直接在内存中匹配接收者
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
// 通过Handler切到主线程分发
mHandler.sendMessage(msg);
}
// handleMessage中逐个调用onReceive
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
推荐替代方案:LiveData、Flow、EventBus。
# 5.4 有序广播的中止与修改
// 有序广播中接收者可以中止和修改结果
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 中止广播(后续接收者不再收到)
abortBroadcast();
// 修改结果(传递给下一个接收者)
setResultCode(Activity.RESULT_OK);
setResultData("modified data");
setResultExtras(bundle);
}
}
// AMS中有序广播的处理
// BroadcastQueue.processNextBroadcastLocked()
// 逐个分发,等待finishReceiver后才发给下一个
// 如果接收者调了abortBroadcast → resultAbort=true → 停止分发
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 06.ContentProvider原理深入分析
# 6.1 Provider的跨进程通信机制
ContentProvider是四大组件中唯一不通过AMS中转每次调用的组件。首次获取Provider时通过AMS,之后直接通过Binder与Provider进程通信:
ContentProvider的通信架构:
首次获取:
Client → AMS.getContentProvider() → 返回IContentProvider Binder代理
后续调用:
Client → IContentProvider.query/insert/update/delete → Provider进程
(不经过AMS,直接Binder通信,效率高)
IContentProvider接口(Binder接口):
query()、insert()、update()、delete()
call() ← 通用方法调用
openFile() ← 文件访问
2
3
4
5
6
7
8
9
10
11
# 6.2 Cursor的数据传输原理
ContentProvider查询返回的Cursor涉及跨进程数据传输:
Cursor的跨进程传输机制:
1.小数据量:直接通过Binder传输
Provider进程创建MatrixCursor/SQLiteCursor
→ 序列化为CursorWindow(共享内存)
→ 通过Binder传递CursorWindow的文件描述符
→ Client进程通过mmap映射读取
2.CursorWindow:
基于匿名共享内存(Ashmem/memfd)
默认大小2MB
支持随机访问,无需全量拷贝
3.大数据优化:
CursorWindow按需加载
Client端通过moveTo*遍历时,如果数据超出当前Window
→ 自动通过Binder请求下一批数据
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 6.3 ContentObserver通知机制
ContentObserver的工作原理:
注册:
ContentResolver.registerContentObserver(uri, notifyForDescendants, observer)
→ ContentService.registerContentObserver()
→ 将observer注册到对应URI的观察者列表
通知:
ContentResolver.notifyChange(uri, observer)
→ ContentService.notifyChange()
→ 遍历匹配URI的所有observer
→ 通过Binder回调onChange()
→ 默认在调用线程回调
→ 可通过Handler指定回调线程
2
3
4
5
6
7
8
9
10
11
12
13
# 6.4 FileProvider的实现原理
FileProvider是ContentProvider的子类,用于安全地共享文件:
FileProvider的工作原理:
1.配置file_paths.xml定义可共享的目录映射
2.FileProvider.getUriForFile()生成content://URI
3.授权:addFlags(FLAG_GRANT_READ_URI_PERMISSION)
4.接收方通过ContentResolver.openInputStream(uri)读取
URI格式:content://authority/path_name/file_name
→ FileProvider内部将path_name映射回实际文件路径
→ 通过openFile()返回ParcelFileDescriptor
安全机制:
- 不暴露真实文件路径
- 可以精确控制授权范围(单个URI或URI前缀)
- 临时授权在目标Activity/Service结束后自动撤销
2
3
4
5
6
7
8
9
10
11
12
13
14
# 07.组件间通信机制
# 7.1 Intent的数据传递原理
Intent是组件间通信的载体,其数据通过Parcel序列化经Binder传输:
Intent的数据承载:
Intent
├── mAction: String(动作)
├── mData: Uri(数据URI)
├── mType: String(MIME类型)
├── mComponent: ComponentName(目标组件)
├── mCategories: Set<String>(类别)
├── mFlags: int(标志位)
└── mExtras: Bundle(附加数据)
Intent的传输过程:
Intent.writeToParcel()
→ 将所有字段序列化到Parcel
→ 通过Binder传输(Binder Driver)
→ 目标进程反序列化:Intent.readFromParcel()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 7.2 Bundle的序列化机制
Bundle内部使用ArrayMap存储键值对,传输时通过Parcel序列化:
Bundle支持的数据类型:
基本类型:int、long、float、double、boolean、String
数组类型:int[]、String[]等
Parcelable:实现了Parcelable接口的对象
Serializable:实现了Serializable接口的对象(性能较差)
Bundle:嵌套Bundle
序列化性能对比:
Parcelable >> Serializable
Parcelable:直接写入Parcel,无反射,速度快
Serializable:使用ObjectOutputStream,大量反射,速度慢
2
3
4
5
6
7
8
9
10
11
# 7.3 Binder传输大小限制
Binder传输限制:
单次Binder事务大小限制:约1MB(准确值为1MB - 8KB的内核头信息)
这个限制是单进程共享的,所有Binder调用共用这1MB缓冲区
TransactionTooLargeException:
当Intent/Bundle数据超过限制时抛出
常见场景:
- onSaveInstanceState保存过多数据
- Intent附带大量数据
- ContentProvider返回过大的Cursor
防御措施:
Intent中的数据应保持精简
大数据使用文件、ContentProvider或共享内存传输
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7.4 大数据传输方案
跨进程大数据传输方案:
1.文件传输:写入文件 → 传递文件路径/URI
2.ContentProvider:通过Cursor或openFile传输
3.共享内存(MemoryFile/SharedMemory):
发送方创建SharedMemory → 写入数据
→ 通过Binder传递ParcelFileDescriptor
→ 接收方mmap映射读取
4.Socket/Pipe:ParcelFileDescriptor.createPipe()
5.AIDL大数据:使用ParcelFileDescriptor传输文件描述符
2
3
4
5
6
7
8
9
# 08.组件的进程间交互
# 8.1 跨进程启动组件的流程
跨进程启动Activity的完整流程:
App-A调用startActivity(intent指向App-B的Activity)
→ Binder IPC到AMS
→ AMS检查App-B的进程是否存在
→ 不存在:通过Zygote fork新进程
→ 新进程启动 → attachApplication回调AMS
→ AMS通知新进程启动目标Activity
→ 存在:直接通知App-B进程启动Activity
→ AMS暂停App-A当前的Activity
→ App-B的Activity显示在前台
2
3
4
5
6
7
8
9
10
# 8.2 远程Service的Binder通信
// AIDL定义接口
// IMyService.aidl
interface IMyService {
String getData(int id);
}
// Service端实现
public class MyService extends Service {
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public String getData(int id) {
return "data_" + id;
}
};
@Override
public IBinder onBind(Intent intent) { return mBinder; }
}
// Client端使用
// bindService后在onServiceConnected中获取代理
IMyService service = IMyService.Stub.asInterface(binder);
String data = service.getData(123); // 跨进程Binder调用
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 8.3 ContentProvider的跨进程查询
ContentProvider的跨进程查询效率较高,因为使用了CursorWindow共享内存:
查询性能优化要点:
1.减少返回列数:只select需要的列
2.使用projection参数:避免select *
3.分页查询:使用LIMIT和OFFSET
4.避免在主线程查询:使用CursorLoader/AsyncTask
5.批量操作:使用ContentProviderOperation.applyBatch()
2
3
4
5
6
# 8.4 PendingIntent的延迟执行
PendingIntent封装了一个Intent和一个操作(startActivity/startService/sendBroadcast),可以传递给其他进程延迟执行:
PendingIntent的原理:
1.创建:PendingIntent.getActivity/getService/getBroadcast
→ 通过AMS注册,返回一个IIntentSender的Binder引用
2.传递:将PendingIntent传给其他进程(如NotificationManager、AlarmManager)
3.执行:其他进程调用PendingIntent.send()
→ 通过IIntentSender.send() → AMS执行原始操作
→ 以创建者的身份和权限执行(不是调用者的权限)
安全意义:
PendingIntent授予了目标进程以你的身份执行指定操作的能力
必须谨慎使用,指定FLAG_IMMUTABLE防止被篡改(Android 12+强制)
2
3
4
5
6
7
8
9
10
11
# 09.组件安全与权限控制
# 9.1 组件的exported属性
exported属性决定组件是否可被其他应用访问:
true → 其他应用可以启动/绑定/发送
false → 仅同一应用(或相同UID)可访问
默认值规则:
- 声明了<intent-filter> → 默认exported=true
- 未声明<intent-filter> → 默认exported=false
- Android 12+:targetSdkVersion>=31的应用必须显式声明exported
安全建议:
- 不需要外部访问的组件必须设置exported=false
- 需要外部访问的组件应配合permission保护
2
3
4
5
6
7
8
9
10
11
12
# 9.2 Permission保护组件
<!-- 定义权限 -->
<permission android:name="com.example.MY_PERMISSION"
android:protectionLevel="signature" />
<!-- 使用权限保护组件 -->
<activity android:name=".SecureActivity"
android:exported="true"
android:permission="com.example.MY_PERMISSION" />
<provider android:name=".MyProvider"
android:authorities="com.example.provider"
android:readPermission="com.example.READ"
android:writePermission="com.example.WRITE" />
2
3
4
5
6
7
8
9
10
11
12
13
AMS在启动组件前会调用PMS检查调用者是否具有所需权限。
# 9.3 签名级权限的应用
signature级别权限只有与定义者相同签名的应用才能获得,适用于同一开发者的多个应用之间的安全通信。
# 9.4 Android 12的安全增强
Android 12+的组件安全增强:
1.exported必须显式声明(targetSdk>=31)
2.PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE
3.精确的Intent匹配:限制隐式Intent的包可见性
4.后台启动限制:禁止后台应用启动Activity和前台Service
2
3
4
5
# 10.总结与面试要点
# 10.1 四大组件对比总结
四大组件对比:
┌──────────┬────────────┬───────────┬────────────┬───────────┐
│ │ Activity │ Service │ Broadcast │ Provider │
├──────────┼────────────┼───────────┼────────────┼───────────┤
│ 用途 │ UI交互 │ 后台任务 │ 事件通知 │ 数据共享 │
│ 有无界面 │ 有 │ 无 │ 无 │ 无 │
│ 通信方式 │ Intent │ Intent/ │ Intent │ URI │
│ │ │ Binder │ │ │
│ 管理者 │ ATMS │ AMS │ AMS │ AMS │
│ 跨进程 │ AMS中转 │ AMS/Binder│ AMS广播 │ 直接Binder │
│ 生命周期 │ 7个回调 │ 按启动方式 │ onReceive │ onCreate │
└──────────┴────────────┴───────────┴────────────┴───────────┘
2
3
4
5
6
7
8
9
10
11
12
# 10.2 高频面试题解析
Q:Activity的生命周期由谁驱动? A:由AMS(ATMS)驱动。AMS通过Binder向应用端发送ClientTransaction,TransactionExecutor计算状态路径并逐个执行生命周期回调。
Q:startService和bindService的区别? A:startService启动后Service与调用者无关联,需显式stopService停止。bindService将Service与调用者生命周期关联,所有绑定者unbind后自动销毁。两者可混合使用,需同时满足两个停止条件才销毁。
Q:静态广播和动态广播的区别? A:静态在PMS注册(Manifest),应用未启动也能接收(Android 8.0+受限)。动态在AMS注册(代码),需进程存活。动态注册走并行队列(快),静态走有序队列(慢)。
Q:ContentProvider为什么在Application.onCreate之前初始化? A:设计上Provider应在应用启动后立即可用(其他进程可能在等待)。AMS在attachApplicationLocked中先让应用安装Provider,再调callApplicationOnCreate。这也是很多库(如LeakCanary)利用Provider实现自动初始化的原因。
# 10.3 最佳实践建议
组件使用最佳实践:
1.Activity:避免在onResume/onPause中做耗时操作,影响切换流畅度
2.Service:优先使用WorkManager替代后台Service,遵守后台限制
3.Broadcast:优先使用动态注册,应用内通信使用LiveData/Flow
4.Provider:使用FileProvider分享文件,避免暴露真实路径
5.通用:组件间传递的数据要精简,避免TransactionTooLargeException
2
3
4
5
6