title: 四大组件启动过程
date: 2020-05-05 13:13:02
tags:[android源码,]
typora-copy-images-to: ./四大组件启动过程
typora-root-url: ./四大组件启动过程
本文主要记录四大组件在framework和APP中如何交互启动.记录大概框架.不追求完备的细节.源码根据8.0
Activity启动过程
主要流程
桌面程序通常是launch.我们点击桌面图标启动app时.是由桌面launch程序通过AMS来启动Activity.这个过程大概如下
image-20200505163411999简单说就是.launch通知AMS启动新Activity. AMS则会先暂停当前进程.然后在启动新进程.然后在新进程启动完成后在创建Activity并启动.
通过intent定位Activity
APP在安装时.通过PackageManagerService 安装.并解析出来AndroidManifest.xml里声明的所有Activity.然后吧主Activity和应用图标绑定起来.这样点击图标.就能找到对应的Activity信息.
Instrumentation启动Activity
execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options){
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
}
这个可以说是代理类,他用来监控程序和系统间的交互.里边有针对Activity启动的监控ActivityMonitor.
他会通过AMS在客户端的代理来通知AMS启动Activity.并且传给AMS一个IBinder类的ApplicationThread,这是用来让AMS回调通知客户端进程的binder本地对象.
同时还传入一个IBinder的 token. 代表当前Activity对象在AMS中的标识. 每个启动的Activity都会有这个token.在AMS端是ActivityRecord对象.
ActivityManager 拿到AMS的代理,进行binder通信
ActivityManager.getService通过ServiceManager 拿到AMS对应的用户端binder.然后包装成AMS的客户端代理.
然后通过binder通信.调用AMS服务端.启动Activity.
image-20200505173538751AMS端处理请求
这里内部会有几个类共同处理.而且每个版本的代码也有所不同.显示AcctivityStack来处理Activity的堆栈管理.
image-20200505173614505PMS解析intent.找到对应的Activity.
PMS在启动的时候,已经解析了所有apk的androidManifest.xml文件.然后就知道所有intent格式对应的Activity.这里会通过PMS来找到合适的Activity.保存在ActivityInfo中.
检查调用进程的权限,封装信息
通过调用进程的ProsessRecord 来在AMS端对应一个用户进程. AMS检查调用者Launcher的进程.看是否有启动Activity的权限等. 同时封装要启动的Activity的信息为ActivityRecord.也拿到了源Activity(也就是launcher)的组件信息.
处理启动标识Intent.FLAG
这里处理各种启动模式,然后产生Activity对应的taskRecord. TaskRecord表示任务栈. 如果这个任务已经存在,就把待启动的Activity加入进去.如果新Activity对应的是新的任务.就要创建新的TaskRecord.
通过管理当前激活的Activity.上次中止的Activity.正在被中止的Activity.AMS来决定把旧Activity(launcher)执行暂停.然后在启动新的Activity.
暂停旧的activity
通过 用户进程的ApplicationThread 在AMS端的代理. AMS通知 旧Activity(launcher) 进行 pause.并把他保存在即将pause的变量中. launcher的Activity在pause后.又会通知AMS他已经pause完毕.然后AMS就会继续执行新Activity的启动过程.
启动新的Activity
先根据新Activity的进程名称判断对应进程是否启动.如果没有启动就先通过zygote来启动新进程.Activity的进程在AMS中的对应的对象是ProcessRecord. 新进程启动完成后必须在规定时间内通知AMS已经启动完成.新进程会执行ActivityThread的main方法.
新进程ActivityThread.main
通过ams.attach.通知AMS 新进程已启动完毕并传入新的ApplicationThread.创建主线程的looper和Handler.开始消息循环.
AMS继续启动Activity
AMS收到ActivityThread的att通知后.继续启动新Activity.此时新进程已经和ProcessRecord对应上.然后通过上边的ApplicationThread在AMS的代理.通知ActivityThread启动Activity.而客户端ApplicationThread收到AMS的消息后.通过向主线程looper 发送消息.启动Activity. ActivityThread收到消息后.取出要启动的Activity信息
ActivityThread 启动Activity
通过执行handleLauncherActivity,反射 创建activity所属的Application.ContextImpl.和activity.
然后执行activity.attach .使activity和WMS建立联系.获得应用窗口.
在执行activity.onCreate. 创建view树.
Activity 的启动.因为之前已经写过了.这里就简单的过一下
Service启动过程
Service的启动分为显示启动和隐式启动.并且可以运行在不同的进程.并且可以通过startService启动.和bindService启动.
activity启动服务
最开始其余 startService. 他会调用到ContextWrapper.startService.有会调用到mBase.startService(service). mBase实际是一个ComtextImpl对象.每个Activity创建时都有一个ContextImpl对象. 他又会调用AMS.startService.通过binder来启动.
AMS接收调用.启动服务
AMS内部又通过 mServices.startServiceLocked 来启动 mService 是ActiveServices类.
ActiveServices.java
startServiceLocked(){
继续启动Service,找到 intent对应的Service.
ServiceLookupResult res =retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
启动完的Service在AMS里抽象为ServiceRecord
ServiceRecord r = res.record;
然后是一些权限的验证处理
生成了一个 ComponentName.这里一会看.
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
通过intent找到Service
ActivityService.java
根据intent.找到对应的Service,在AMS里.每个ServiceRecord是和ComponentName绑定的
private ServiceLookupResult retrieveServiceLocked(Intent service...){
ServiceRecord r = null;
找到进程对应的 ServiceMap.然后根据componentName找Service.
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
接下来是对ServiceRecord 权限的检查,看用户进程是否可以启动这个Service
最后封装后返回出去
return new ServiceLookupResult(r, null);
}
启动服务 startServiceInnerLocked
这里又调用的同名函数 bringUpServiceLocked 这是真正启懂Service的地方.然后又调度队列.启动所以等待的Service
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r...){
//启动Service
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
//通过队列.把等待启动的Service 再次通过startServiceInnerLocked方法启动.
if (r.startRequested && addToStarting) {
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);
}
}
AMS启动service对应进程
这里会看Service对应的进程是否启动.如果启动.就直接启动Service就行了.如果没有.就先启动对应的进程.进程在AMS端的代表对象是ProsessRecord
private String bringUpServiceLocked(ServiceRecord r){
进程存在,直接启动Service
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
进程不存在.启动进程,然后在把Service放入队列,等待启动
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
}
AMS启动Service的进程,这里还是通过Process.start来启动新进程.这里和之前的Activity比较类似.也是通过zygote进程来fork出新进程.然后执行ActivityThread的main函数. 进程初始化完成后.会调用AMS.attachApplication.
这里和Activity的启动是一个方法.这次他会在这里看上边加入队列的
ActivityManagerService.java
boolean attachApplicationLocked(IApplicationThread thread,int pid) {
又回调到了Service的方法区去处理启动Service
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true;
}
}
}
Service继续启动服务
遍历pending队列,启动Service
ActivityServices.java
boolean attachApplicationLocked(ProcessRecord proc, String processName) {
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
realStartServiceLocked(sr, proc, sr.createdFromFg);
}
}
}
realStartServiceLocked里最主要的是,下边的.也就是通过binder调用用户进程启动service,通过ApplicationThread继而通知ActivityThread启动服务
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),app.repProcState);
用户进程启动service
ActivityThread.java
void handleCreateService(CreateServiceData data) {
每个app都有一个loadedApk来描述应用程序的资源.
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
反射加载servi的类.
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
为service创建ContextImpl上下文环境. activity也有这个.
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
service 绑定Application. 执行onCreate
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
ActivityThread 保存所有的service
mServices.put(data.token, service);
try {
通知AMS.service启动成功
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
}
}
最后AMS里会做一些收尾工作.
附一个流程图.
Sample sequence diagramservice绑定过程
绑定的Service也是需要先启动起来的. 过程和启动服务类似. 都是从ContextImpl通知AMS开始.这里会封装一个IServiceConnection.这个IServiceConnection 是一个adil类.这是夸进程传递给AMS 的对象. 这里.APP的进程是IServiceConnection的binder服务端. AMS则持有 IServiceConnection的binder的代理端.
封装ServiceConnect.通知AMS
bindServiceCommon(Intent service, ServiceConnection conn,){
IServiceConnection sd;
//封装成一个IBinder.
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
// 调用ams的方法.
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
}
AMS转给ActiveServices处理.
这里的流程比较复杂.简单说就是找到service的记录.然后和对应的Activity. 及Activity对应的process创建绑定关系ConnectionRecord并保存起来.保存在service 的ServiceRecord中.然后开始启动service
ActivityServices.java
bindServiceLocked (IApplicationThread caller, IBinder token, Intent service, final IServiceConnection connection..){
请求绑定服务的Activity的进程.
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
请求的Activity的记录
ActivityRecord activity = null;
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
}
//同启动服务一样.找到对应的service记录.
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
ServiceRecord s = res.record;
找到service对应的app绑定描述对象.表示service绑定在callerApp进程中.表示绑定在这个service上的进程.
这是一种对应关系. 一个service可以被多个进程绑定.
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
这里是描述Activity.service.process 的对应关系的一个记录.
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
得到connection的远程代理类.,保存上边的映射关系.
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
接着启动这个service
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
clist.add(c);
c.conn.connected(s.name, b.intent.binder, false);
}
ActivityServices 继续启动
bringUpServiceLocked方法.在启动service里已经出现过了.流程就是启动service对应的进程. 进程启动完后通知AMS.AMS在通知创建Service. 直到执行service的onStart.onCreate
但是这里不太一样的是realStartServiceLocked里又会执行requestServiceBindingsLocked.进而遍历调用r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState); 也就是变量得到该service所有对应的要绑定的activity的相关记录.
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if ((!i.requested || rebind) && i.apps.size() > 0) {
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
}
return true;
}
ActivityThread处理绑定服务
这时.又通过Binder通知到了ActivityThread,他调用servic的onBind. 获取服务的binder对象.然后回传给AMS
ActivityThread.java
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
try {
if (!data.rebind) {
调用了service的onBind 获取service的 binder. ActivityThread保存所有的service.
IBinder binder = s.onBind(data.intent);
再把service服务的binder传递个AMS.用来发送回所有绑定到该service的进程.当然发送过去的是本地binder的代理类.
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
}
AMS获取service的binder代理对象
ams还是把请求交个ActivityServices来处理.
ActivityServices.java
publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
Intent.FilterComparison filter= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
ConnectionRecord是上问我们介绍的 service和Activity和acitivity的process建立的绑定关系.
这里拿到这个服务的所有ConnectionRecord.然后取出里边的binder代理类 IServiceConnection.
在调用connected方法.并传入service发过来的binder. 就实现了 service和Activity的绑定.
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
c.conn.connected(r.name, service, false);
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
看到这里就明白了. activity提供的ServiceConnection 被包装成Binder后.发送到AMS中.与要绑定的Service建立关系.产生ConnectionRecord对象. 而service在对应的进程启动完成.service也启动完成后. 由AMS调用service 的onBind. service 则会提供代表他的功能的binder给AMS. 在publishServiceLocked方法中.遍历所有的ConnectionRecord, 调用conn.connected 把service 传来的binder发送给 activity里的ServiceConnection .这就实现了 activity和service的绑定.
ServiceDispatcher 处理connection
上边的 c.conn.connected(r.name, service, false); 其实是调用的的InnerConnection的方法.他是LoadApk 里ServiceDispatcher的内部类.是aidl实现的类.这里又涉及到AMS和最初 的Activity 通过aidl 方式来进程ipc.
loadApk.java
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
可以看到.通过handler.把connec推到住线程来处理了.
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
Runnconection 在主线程处理
简单说就是找到旧的服务.将他断开,然后执行新的connection 的onServiceConnected方法.也就是回调activity里设置的connection.
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
}
old = mActiveConnections.get(name);
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
断开旧服务
if (old != null) {
mConnection.onServiceDisconnected(name);
}
开启新服务
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
Service_Start
广播机制
广播机制是在binder的基础上实现的.广播机制存在注册中心.就是AMS.广播订阅者要先向AMS注册,并指明接受广播的类型.然后广播发送者把广播发送给AMS.再由AMS分发给对应的接收者.
广播分为有序广播和无序广播. 注册时有静态注册和动态注册.
注册广播
同样是从ContextImpl开始.先拿到主线程的handler.然后封装一个 receiverDispatcher.然后通知AMS来注册,
这个ReceiverDispatcher也是对receiver的封装.并且内部有实现aidl 的类.也就是利用binder 把代理类发给AMS.用于回调.
ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
封装一个receiverDispatcher .这个和service原理有点类似.都是发给AMS用来回调app进程的binder类
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
还拿到了ui线程的handler,用来向主线程发消息.
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
}
}
通过ams注册
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
}
AMS中注册广播
这里有对粘性广播和普通广播的处理. 如果存在粘性广播.就把他们保存在 allSticky中.粘性广播就是广播发送在广播注册之前.但是也能收到.粘性广播会一直留在AMS中.直到下一个同类型粘性广播的到来.
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
callerApp = getRecordForAppLocked(caller);
instantApp = isInstantApp(callerApp, callerPackage, callingUid);
找到匹配的粘性广播,保存intent
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
if (filter.match(resolver, intent, true, TAG) >= 0) {
allSticky.add(intent);
}
}
}
每个广播接收者是用BroadcastFilter 来描述.BroadcastFilter和APP传过来的InnerReceiver.而可能多个activity会使用同一个InnerReceiver.因此用集合来保存相同InneReceiver的广播接收者.
也就是如果多个activity注册同一个广播.就会有一个InnerReceiver.对应多个BroadcastFilter.
synchronized (this) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
加到这里后.以后来了广播.就能找到对应的接收者.
mReceiverResolver.addFilter(bf);
把粘性广播返回给activity组件.也就实现了粘性广播的发送.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
final int stickyCount = allSticky.size();
for (int i = 0; i < stickyCount; i++) {
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
每个广播对应的就是 BroadCastRecord 记录.这里是入栈.然后发送粘性广播.
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
发送广播
首先广播发送者把广播发送给AMS.
然后AMS找到这个广播对应的接收者,再把这个广播和接收者添加到广播队列中.并向AMS中发送一个BROADCAST_INTENT_MSG的消息.等待AMS处理.
当AMS处理到这个消息时,取出广播及接收者,分别将广播发给接收者的进程
接受者进程的ActivityThread会再次把消息发送到主线程的消息队列.等消息被处理时在交给广播接收者.
发送广播给AMS
由ContextImpl 通过binder通信把广播发给AMS.
AMS接收处理广播
broadcastIntent()
验证广播intent参数的合法性.
broadcastIntentLocked()
先是对intent里的action的不同类型的处理.如检查权限.同时对系统广播进行处理.
接着是对粘性广播的处理.所有的粘性广播都保存在一个hashmap中,并已action作为key
然后如果广播指定了接收者的Component.就从pms中找到对应的接收者,保存起来
然后在判断intent的flag 是发给动态接收者还是动态接收者以及静态接收者.静态和动态的广播接收者分别保存在不同的集合中.
针对无序广播.并且有动态接收者.在发给静态接收者.封装成BroadcastRecord,加入队列.
接着把剩下的广播都加入到BroadcastQueue,并且接收者会按照优先级排序.合并静态动态接受者.
BroadcastQueue.scheduleBroadcastsLocked
将广播加入队列后.通过handler发送给AMS的线程.可以看到广播的发送和接收是异步的
BroadcastQueue.processNextBroadcast
取出广播对象BroadcastRecord,处理无序广播队列,找到所有的无序接收者.遍历执行deliverToRegisteredReceiverLocked
然后执行有序广播的处理. 如果对应的广播接收者还没启动.则先启动对应的进程,然后继续处理下一个有序广播接收者.
入股有序广播不能再一个限定时间内处理完成.就会结束这个有序广播.
BroadcastQueue.deliverToRegisteredReceiverLocked
这里AMS把广播转发给APP所在进程.其实是通过回调ApplicationThread的scheduleRegisteredReceiver把消息发给ActivityThread的.这时发送给APP进程的是之前包装过的InntentReceiver的代理类. 他内部封装了一个广播接收者.
ActivityThread.scheduleRegisteredReceiver
这里就到了APP进程.然后由之前传入的InnerReceiver 来继续执行.
他内部会发消息给ActivityThread的主线程. 发一个runnable过去.等主线程处理这个消息. runnable是Args
的内部类.
Args.getRunnable
最后调用receiver.onReceive .也就是接收者接收到了消息.然后在回调AMS.finishReceive表示消息接收完成
contentprovider 以后再补充.他是用共享内存作为夸进程传输数据的.
网友评论