写在开头:本文为读书笔记。
本篇大部分文字来自《深入理解Android内核设计思想》,小部分图文是阅读《深入理解Android内核设计思想》过程中的思考的问题(因为带着问题点去看才能印象深刻),参考部分博客,我有给出链接,小部分是自己结合源码的理解。部分源码未详细开展,本文目的是梳理大致流程。另外,代码最好放到Android studio里面去看,网页上看代码一多的话跳转很麻烦。
Binder可以分为4部分。
• Binder 驱动
• Service Manager
• Binder Client
• Binder Server
如果统观Binder 中的各个组成元素,就会惊奇地发现它和TCP/IP 网络有很多相似之处。
• Binder 驱动一路由器
• Service Manager一DNS
• Binder Client一客户端
• Binder Server一服务器
深入理解Android内核设计思想
接下来我会带着问题去分析binder的大致工作原理,这里主要分析binder驱动和Service Manager。
1.binder驱动
Binder Driver 会将自己注册成一个misc device, 并向上层提供一个/dev/binder 节点——值得一提的是, Binder 节点并不对应真实的硬件设备。Binder 驱动运行于内核态,可以提供open(), ioctl(), mmap()等常用的文件操作。
首先,问题一:为什么Binder 驱动只用了一次复制,
就实现了进程间的数据共享
首先要理解Android进程空间。
首先,对于一个32位的处理器, 在Linux系统中,其虚拟地址为32位,因此其虚拟地址空间的范围为
一个可执行文件运行起来的话它就变成了进程,系统会给每个进程分配一个4G大小的虚拟地址空间。如果一个Android设备是8g内存,给每个进程分配4g实际内存是不可能的。
Linux系统将虚拟地址空间按3:1比例划分,其中用户空间(user space)占3GB,内核空间(kernel space)占1GB。其中前3G内存是用户空间,最后1G是内核空间。所有的进程有各自的用户空间,但所有的进程都共享一个内核空间。
对应关系大致如下(对应关系是乱画的),实际是通过页表,找到实际的物理内存地址。
操作系统_存储模型
假设有两个进程A 和B, 其中进程B 通过open()和mmap()后与Binder 驱动建立了联系。
什么是mmap:内存映射文件。
进程通过一个系统调用(mmap)将一个文件(或部分)映射到其虚拟地址空间的一部分,访问这个文件就象访问内存中的一个大数组,而不是对文件进行读写。
对于进程B而言, 它通过mmap()返回值得到一个内存地址(当然这是虚拟地址),这个地址通过虚拟内存转换(分段、分页)后最终将指向物理内存的某个位置。对千Binder 驱动而言,它也有一个指针( binder_proc->buffer )指向某个虚拟内存地址。而经过虚拟内存转换后,它和应用程序中指向的物理内存处千同一个位置。
这时Binder 和应用程序就拥有了若干共用的物理内存块。换句话说, 它们对各自内存地址的操作,实际上是在同一块内存中执行的。
右半部分Binder 驱动通过copy_from_ user() , 把进程A 中的某段数据复制到其binder_proc->buffer
所指向的内存空间中。这时候我们惊喜地发现, 因为binder_proc->buffer 在物理内存中的位置和进程B 是共享的, 因而进程B 可以直接访问到这段数据。也就是说, Binder 驱动只用了一次复制,就实现了进程A 和B 间的数据共享。
进程和binder通讯大致如下所示。
https://blog.csdn.net/codefly/article/details/17058607?spm=1001.2014.3001.5501以下是简单的进程间通讯图。
https://juejin.cn/post/6857132425781182477
native层这里涉及到几个类。BpBinder
和BBbinder
。
binder机制中,C++层次的继承关系图如下:
image.png
https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android10-c2f2-release/libs/binder/BpBinder.cpp
// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
BpBinder* BpBinder::create(int32_t handle) {
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
AutoMutex _l(sTrackingLock);
uint32_t trackedValue = sTrackingMap[trackedUid];
if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
if (sBinderProxyThrottleCreate) {
return nullptr;
}
} else {
if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
if (sLimitCallback) sLimitCallback(trackedUid);
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
" count drops below %d",
trackedUid, getuid(), sBinderProxyCountLowWatermark);
return nullptr;
}
}
}
sTrackingMap[trackedUid]++;
}
return new BpBinder(handle, trackedUid);
}
BBbinder定义在Binder.cpp中。
https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android10-c2f2-release/libs/binder/Binder.cpp
// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != nullptr) {
reply->setDataPosition(0);
}
return err;
}
// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
switch (code) {
case INTERFACE_TRANSACTION:
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
case DUMP_TRANSACTION: {
int fd = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
return dump(fd, args);
}
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
sp<IShellCallback> shellCallback = IShellCallback::asInterface(
data.readStrongBinder());
sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
data.readStrongBinder());
// XXX can't add virtuals until binaries are updated.
//return shellCommand(in, out, err, args, resultReceiver);
(void)in;
(void)out;
(void)err;
if (resultReceiver != nullptr) {
resultReceiver->send(INVALID_OPERATION);
}
return NO_ERROR;
}
case SYSPROPS_TRANSACTION: {
report_sysprop_change();
return NO_ERROR;
}
default:
return UNKNOWN_TRANSACTION;
}
}
BBinder用于server端,BpBinder用于client端。
例如BpMediaPlayer和BnMediaPlayerService,就类似是Bpxxx和Bnxxx。
具体分析可参考这篇。
Android之MediaPlayer 基本类_CAESAR的专栏-CSDN博客
BpBinder的实例的transact会调用BBbinder实例的transact,最终调用BBbinder中的onTransact。
其实这是一个Proxy-Stub模式。Proxy Stub即代理和存根。
打个比方,你到自动取款机上去取款;你就是客户,取款机就是你的代理;你不会在乎钱具体放在那里,你只想看到足够或更多的钱从出口出来(这就是com的透明性)。你同银行之间的操作完全是取款机代理实现。 你的取款请求通过取款机,传到另一头,银行的服务器,他也没有必要知道你在哪儿取钱,他所关心的是你的身份,和你取款多少。当他确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。 取款机不是直接同服务器连接的,他们之间还有一个“存根”,取款机与存根通信,服务器与存根通信。从某种意义上说存根就是服务器的代理。
第二个问题来了。
问题二:binder驱动是如何从代理对象找到其对应的binder实体呢?
binder代理对象是指BpBinder实例,也就是BpXXX。
它是在用户空间创建,并且运行在Client进程中。
binder实体是指BBinder实例,也就是BnXXX,运行在Service进程中。
回到问题,这里主要是靠binder_proc(定义在kernel中)中的4棵红黑树。
//https://github.com/Iscle/OrangePi_4G-IOT_Android_8.1_BSP/blob/58548740b6e9afe99a55b77582588c37609d2bca/kernel-4.4/drivers/android/binder.c
struct binder_proc
{
. . . . . .
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
. . . . . .
. . . . . .
};
有四颗红黑树。nodes树用于记录binder实体,refs_by_desc树和refs_by_node树则用于记录binder代理。之所以会有两个代理树,是为了便于快速查找,threads树用于记录执行传输动作的线程信息。
BpBinder
到底是如何和BBinder
联系上可以参考下图:https://blog.csdn.net/codefly/article/details/17058673?spm=1001.2014.3001.5501
BpBinder
通过binder
的句柄,即handle
,其实就是
BpBinder
调用create
的时候传入的一个int型的参数,BpBinder* BpBinder::create(int32_t handle)
。
当BpBinder
创建后,会持有一个句柄。
BpBinder通过handle查询BBinder地址流程如下:
1.binder
驱动查找binder_proc
结构和句柄值相符的binder_ref节点
2.通过binder_ref
节点的node域找到对应的binder_node
节点,这个目标binder_node
当然是从属于进程2的binder_proc
啦,因为binder_ref
和binder_node
都处于binder
驱动的地址空间中,所以是可以用指针直接指向的。
3.binder_node
节点的cookie
域,记录的其实是BBinder
的地址,binder
驱动只需把这个binder
实体对象地址值返回即可。
所以问题二的总结版答案是:首先通过代理对象BpBinder
的handle
找到binder_proc
中binder_ref
存储的node
域,然后把node
域中的cookie
域(cookie
域记录了BBinder
实体对象的地址),通过binder驱动把传cookie
域所记录的Binder实体对象地址值给client进程。
其实这里还有一个问题点,如何通过handle
找?这里涉及到ServiceManager
部分,放到后面去。
2.ServiceManager
ServiceManager 在Android 系统启动之后就运行起来了,并通过BINDER_SET_CONTEXT_MGR 把自己注册成Binder “ 大管家”。它在做完一系列初始化后,在最后一次ioctl 的read 操作中会进入睡眠等待,直到有Binder Client 发起服务请求而被Binder 驱动唤醒。
这一部分我只看java层。
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android10-c2f2-release/core/java/android/os/ServiceManager.java
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static final Object sLock = new Object();
@UnsupportedAppUsage
private static IServiceManager sServiceManager;
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
/**
* Returns a reference to a service with the given name.
*
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
@UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name the name of the new service
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* to access this service
*/
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated) {
addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
}
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name the name of the new service
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* @param dumpPriority supported dump priority levels as a bitmask
* to access this service
*/
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
}
ServiceManager
中主要是调用add和get方法。
下面以StatusBarManagerService
为例,来看看ServiceManager
的使用。
如果只看java层的话,主要涉及到StatusBarManagerService
,StatusBarManager
,StatusBar
,CommandQueue
这4个类。
SystemServer
中的startOtherServices
,将StatusBarManagerService
添加到ServiceManager
中。
StatusBarManagerService
是继承自IStatusBarService.Stub
。
//https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
StatusBarManagerService statusBar = null;
......................
if (!isWatch) {
t.traceBegin("StartStatusBarManagerService");
try {
statusBar = new StatusBarManagerService(context);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
t.traceEnd();
}
...................
}
先不看client端的调用,只看service这一端的流程。
下面是省略版IStatusBarService.aidl和IStatusBar.aidl文件。
注意:为减少文件,我有删除部分函数的参数。
import xxx.xxx.xxx.IStatusBar;
interface IStatusBarService {
void removeIcon(String slot);
void registerStatusBar(IStatusBar callbacks);
}
oneway interface IStatusBar {
void removeIcon(String slot);
}
statusbar中一个图标对应一个slot。
可以新建这2个aidl文件到Android studio中,然后build一下工程,看看生成的java文件。
StatusBarManagerService继承自IStatusBarService.Stub, 是BBinder。CommandQueue 继承自IStatusBar.Stub,
public class StatusBarManagerService extends IStatusBarService.Stub {
private volatile IStatusBar mBar;
@Override
public void removeIcon(String slot) {
enforceStatusBar();
synchronized (mIcons) {
mIcons.remove(slot);
if (mBar != null) {
try {
mBar.removeIcon(slot);
} catch (RemoteException ex) {
}
}
}
}
@Override
public void registerStatusBar(IStatusBar bar) {
mBar = bar;
}
}
public class CommandQueue extends IStatusBar.Stub{
private ArrayList<Callbacks> mCallbacks = new ArrayList<>();
public interface Callbacks {
default void removeIcon(String slot) { }
}
public void addCallback(Callbacks callbacks) {
mCallbacks.add(callbacks);
}
public void removeIcon(String slot) {
synchronized (mLock) {
// don't coalesce these
mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget();
}
}
private final class H extends Handler {
private H(Looper l) {
super(l);
}
public void handleMessage(Message msg) {
final int what = msg.what & MSG_MASK;
switch (what) {
case MSG_ICON: {
switch (msg.arg1) {
case OP_REMOVE_ICON:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).removeIcon((String) msg.obj);
}
break;
}
break;
}
}
}
}
}
再来看StatusBar 。
public class StatusBar implements CommandQueue.Callbacks{
protected CommandQueue mCommandQueue;
protected IStatusBarService mBarService;
public StatusBar(CommandQueue commandQueue){
mCommandQueue = commandQueue;
}
@Override
public void start() {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mCommandQueue.addCallbacks(this);
try {
mBarService.registerStatusBar(mCommandQueue);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
这里终于看到了ServiceManager。前面SystemServer.java中调用了 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
,StatusBar.java
中,调用了getService。
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
也就是这里是 IStatusBarService.Stub.asInterface(StatusBarManagerService)。
//IStatusBarService.java
public static com.example.myapplication.IStatusBarService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.myapplication.IStatusBarService))) {
return ((com.example.myapplication.IStatusBarService)iin);
}
return new com.example.myapplication.IStatusBarService.Stub.Proxy(obj);
}
Stub.asInterface这里会根据调用进程与当前进程是否一致判断返回Bbinder(Binder实体)还是BpBinder(本地Binder的代理对象,即IStatusBarService.Stub.Proxy)。
如果忽略掉binder驱动层,可以看成这里是返回一个StatusBar可以调用的StatusBarManagerService实例。
mBarService.registerStatusBar(mCommandQueue);
StatusBar
中调用了mBarService.registerStatusBar(mCommandQueue);
因此StatusBarManagerService
持有CommandQueue
。
所以,当调用StatusBarManagerService 的removeIcon(String slot)的时候,会走到CommandQueue
的 mCallbacks.get(i).removeIcon((String) msg.obj);
中。
这里使用了回调。
removeIcon实际的具体的实现是在StatusBarIconControllerImpl
中。
public class StatusBarIconControllerImpl implements CommandQueue.Callbacks,StatusBarIconController {
@Inject
public StatusBarIconControllerImpl(Context context, CommandQueue commandQueue) {
mContext = context;
commandQueue.addCallback(this);
}
public void removeIcon(String slot) {
removeAllIconsForSlot(slot);
}
@Override
public void removeAllIconsForSlot(String slotName) {
Slot slot = getSlot(slotName);
if (!slot.hasIconsInSlot()) {
return;
}
int slotIndex = getSlotIndex(slotName);
List<StatusBarIconHolder> iconsToRemove = slot.getHolderListInViewOrder();
for (StatusBarIconHolder holder : iconsToRemove) {
int viewIndex = getViewIndex(slotIndex, holder.getTag());
slot.removeForTag(holder.getTag());
mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
}
}
}
如果需要aidl中新增一个其他控制函数,也可以把具体实现写到StatusBar
,看具体需求。
至于StatusBar
和StatusBarIconControllerImpl
的创建,涉及到依赖注入与控制反转,这里不做深入,可参考这一篇文章去具体分析。Dagger2和它在SystemUI上的应用
Android源码中其实很多模块用到了依赖注入与控制反转。
service端的分析就到这里了,下面来看看client端。
这里主要就是StatusBarManager
。
@SystemService(Context.STATUS_BAR_SERVICE)
public class StatusBarManager {
private IStatusBarService mService;
private synchronized IStatusBarService getService() {
if (mService == null) {
mService = IStatusBarService.Stub.asInterface(ServiceManager.getService(STATUS_BAR_SERVICE));
}
return mService;
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void removeIcon(String slot) {
try {
final IStatusBarService svc = getService();
if (svc != null) {
svc.removeIcon(slot);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
frameworks/base/core/java/android/app/SystemServiceRegistry.java
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
@Override
public StatusBarManager createService(ContextImpl ctx) {
return new StatusBarManager(ctx.getOuterContext());
}});
StatusBarManager
在SystemServiceRegistry
中初始化。
mService = IStatusBarService.Stub.asInterface(ServiceManager.getService(STATUS_BAR_SERVICE));
这里也是通过ServiceManager
和IStatusBarService
获取一个Binder,不过由于是不同进程所以这里获取的是Binder代理对象。
StatusBarManager
类定义的时候用@SystemService(Context.STATUS_BAR_SERVICE)
修饰,因此
获取StatusBarManager
可以通过getSystemService
。
StatusBarManager mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
或
StatusBarManager mStatusBarManager = (StatusBarManager) getSystemService(StatusBarManager.class);
然后会在StatusBarNotifier
调用 mStatusBarManager.setIcon
。
//https://cs.android.com/android/platform/superproject/+/master:packages/services/Telecomm/src/com/android/server/telecom/StatusBarNotifier.java
if (isMuted) {
mStatusBarManager.setIcon(
SLOT_MUTE,
android.R.drawable.stat_notify_call_mute,
0, /* iconLevel */
mContext.getString(R.string.accessibility_call_muted));
} else {
mStatusBarManager.removeIcon(SLOT_MUTE);
}
StatusBarNotifier会由一个client去调用,应该是某个telecom相关进程。
简单来说,removeIcon的调用过程如下。
这张图是只是java代码部分,忽略了c++部分代码,实际java到驱动中间是通过jni去调用c++代码,c++代码访问binder驱动
大致流程就是这样的。
http://gityuan.com/2015/11/21/binder-framework/StatusBarManagerService
就是一个BinderProxy,
如何设计到native层的话,这里还有一个问题:Client如何通过ServiceManager创建BpBinder?
问题3可以参考这篇。
深入理解任何Binder Client都可以直接通过ServiceManager的0这个Binder句柄创建一个BpBinde
这个问题我暂时没有捋清楚,代码还没有过一遍。
总结:
如果要访问SM(Binder Server)的服务,流程应该是怎么样的呢?
无非就是以下几步:
· 打开Binder 设备;
· 执行mrnap;
· 通过Binder 驱动向SM 发送请求( SM 的handle 为0) ;
· 获得结果。
如果应用程序代码中每次使用SM 服务( 或者其他Binder Server 服务),都需要打开一次Binder 驱动、执行mmap , 其后果就是消耗的系统资源会越来越多, 直到崩溃。一个有效的解决办法是每个进程只允许打开一次Binder 设备, 且只做一次内存映射一一所有需要使用Binder 驱动的线程共享这一资源。
ProcessState 和IPCThreadState
Android 系统特别为程序进程使用Binder 机制封装了两个实现类,即ProcessState 和IPCThreadState。从名称上可以看出,前者是进程相关的,而后者是线程相关的。ProcessState 负责打开B inder 驱动设备,进行mmap等准备工作; 而如何与Binder 驱动进行具体的命令通信则由IPCThreadState 来完成。
ProcessState 的构造函数中初始化了很多变量—最重要的是,它调用open_driver()打开了/dev/binder 节点。我们再复习一下使用Binder 驱动所需要做的准备工作: 首先是打开binder 节点,然后执行mmap()一具体而言,映射的内存块大小为BINDER_VM_SIZE 。
真正与Binder 驱动打交道的地方是talkWithDriver 中的ioctl(),整个流程中多次调用了这个函数。
Binder 的执行过程多数是阻塞型的( 或者说是同步操作)。换句话说,通过Binder去调用服务进程提供的接口函数,那么此函数执行结束时结果就已经产生,不涉及回调机制。比如用户使用getService 向ServiceManager 发起查询请求一函数的返回值就是查询的结果,意味若用户不需要提供额外的回调函数来接收结果。
Binder 是如何做到这一点的呢?可以想到的方法有很多, 其中常见的一种就是让调用者进程暂时挂起,直到目标进程返回结果后, Binder 再唤醒等待的进程。
因为一个transcation 通常涉及两个进程A 和B , 当A 向B 发送了请求后, B 需要一段时间来执行:此时对A 来说就是一个“未完成的操作“一直到B 返回结果
后, Binder 驱动才会再次启动A 来继续执行。
关于Binder的传输,我觉得结合AIDL去说明比较好,所以留到下一篇。有空的话在写。
参考链接:
《深入理解Android内核设计思想》
Dagger2和它在SystemUI上的应用
图解Android - Binder 和 Service - 漫天尘沙 - 博客园
红茶一杯话Binder(初始篇)
Android之MediaPlayer 基本类_CAESAR的专栏-CSDN博客
Android深入浅出之Binder机制 - innost - 博客园
深入理解任何Binder Client都可以直接通过ServiceManager的0这个Binder句柄创建一个BpBinde
Binder本地对象,实体对象,引用对象,代理对象的引用计数_jltxgcy的专栏-CSDN博客
为什么 Android 要采用 Binder 作为 IPC 机制?
网友评论