}
return new com.rikkatheworld.aidl_demo.IUserManager.Stub.Proxy(obj);
}
…
可以看出调用了 queryLocalInterface()
获得一个 IInterface类型的对象iin,如果iin不为空,则返回iin,如果为空,则 new一个 Proxy类并返回。
我们知道AMS给我们返回的一定是Binder的对象,所以我们去 Binder中看看queryLocalInterface()
:
// Binder.java
public class Binder implements IBinder {
…
// 1
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
…
}
// 2
final class BinderProxy implements IBinder {
// 3
public IInterface queryLocalInterface(String descriptor) {
return null;
}
…
}
可以发现Binder文件中,有两处实现了这个方法,在Binder类中。
注释1中 通过 descriptor标识来返回,mOwner是Bidner本身。
注释2、3是 BinderProxy
实现的,直接返回一个空。
在Stub类的构造方法里我们就看到了只要Stub
被构建就会调用:
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
按理来说,queryLocalInterface
不可能返回为空,我们应该都是得到一个正宗的 Stub类才对,但是实际上这里出现了偏出。
在跨进程服务中,我们通过 asInterface() 返回的是一个 IUserManager.Stub.Proxy
的对象。这就说明 queryLocalInterface()
返回了空,只有一种情况会导致这种结果, 那就是 ServiceConnection返回来的值是一个 BinderProxy
类型的对象。
这就是我最开始的疑问点,为什么 onServiceConnection()
中远端进程和同进程下返回的是Binder,而不同进程下返回的是BinderProxy
。
Binder机制是C/S架构,任意两个进程,请求方是C端,接收方是S端
C端通过 BpBinder
来访问S端,S端通过 BBinder
来访问C端,而BpProxy
就是BpBinder的封装类。他们的具体知识这里就不再赘述了。详情请看皇叔的文章。下面以框架层角度画个图来看下 客户端进程的数据传出经过了什么方法:
万物的开端在于BindService,在 Service的startService和bindService源码流程中,我们知道主进程的最终代码是到 ContextImpl.bindServiceCommon()
:
// ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException(“Not supported in system context”);
}
…
try {
IBinder token = getActivityToken();
…
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
…
} …
}
// ActivityManager
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
ActivityManager.getService()是 IActivityManager.Stub.asInterface(b)
,这个肯定是Proxy类(套娃了,不过问题不大),我们要来看看bindService做了什么,由于IActivityManager是编译产生的,所以我暂时还没有找到IActivityManager,但是我们知道 它的实现肯定和我们自己所编译出来的如出一辙,甚至我们自己都可以写出来:
// 这个地方是照着 IUserManger.Stub.Proxy 仿写的,也看了开篇Blog的内容
// IActivityManager.Stub.Proxy
@Override
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain(); // 1
android.os.Parcel _reply = android.os.Parcel.obtain(); // 2
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(caller != null ? caller.asBinder() : null); // 3
_data.writeStrongBinder(token); // 4
service.writeToParcel(data, 0);
_data.writeString(resolvedType);
_data.writeStrongBinder(connection.asBinder()); // 5
_data.writeInt(flags);
_data.writeInt(userId);
mRemote.transact(TRANSACTION_bindService, data, reply, 0); // 6
reply.readException();
_result = reply.readInt(); // 7
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
注释1:获得一个传出去的序列化数据 data
注释2:获得一个用于接收的序列化数据 reply
注释3、4、5: 通过 writeStrongBinder()
把 Binder数据写入到 data中
注释6:调用原生层的 transact()
,传入数据
注释7:在返回结果reply读出数据result
其中,注释3、4、5、6是这个方法的关键。就是参数是这么从客户端进程传出去的。
我们来看看 writeStrongBinder()
,它是一个native方法:
// frameworks/base/core/jni/android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
这里调用了两个函数, 一个是调用了 ibindForJavaObject
得到一个IBinder,在传入到 Parcel->writeStrongBinder()
中:
先来看看前者
// frameworks/base/core/jni/android_os_Parcel.cpp
sp ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL; // 1
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject); // 2
}
return NULL;
}
注释1:如果传进来的binder是 gBinderOffsets,则 new一个 JavaBBinder
并返回。
注释2:如果传进来的bind是 gBinderProxyOffsets(代理类),类中的 代理对象。(也就是封装在里面了,取出来用)
由于我们是客户端进程,所以进来的并不是代理类,所以 ibinderForJavaObject()
会返回一个 JavaBBinder返回给我们。
再来看看 Parcel.writeStrongBinder():
// frameworks\native\libs\binder\Parcel.cpp
status_t Parcel::writeStrongBinder(const sp& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp& /proc/,
const sp& binder, Parcel* out)
{
…
if (binder != NULL) {
IBinder *local = binder->localBinder(); // 1
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE(“null proxy”);
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don’t pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
obj.type = BINDER_TYPE_BINDER; // 2
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
inline static status_t finish_flatten_binder(
const sp& /binder/, const flat_binder_object& flat, Parcel* out)
{
return out->writeObject(flat, false);
}
在writeStrongBinder中调用了 flatten_binder()
,
注释1:localBinder()是取出Binder中的数据,用来标识传入Binder的进程是否是当前进程,所以local不为null,会走到else中去
注释2:设置 type为 BIND_TYPE_BINDER
最后把这些数据写到输出数据中。也就是一开始我们的 _data。
接下来看下 mRemote.transact()
这个方法,mRemote是 ServiceManager
返回给我们的,它是一个 BinderProxy对象,所以会调用 BinderProxy.transact()
:
// Binder.java
// BinderProxy ->
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
…
try {
return transactNative(code, data, reply, flags);
} …
}
调用了 native层的 transactNative()
:
// android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
…
Parcel* data = parcelForJavaObject(env, dataObj); // 1
…
Parcel* reply = parcelForJavaObject(env, replyObj); // 2
…
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject); // 3
…
status_t err = target->transact(code, *data, reply, flags); // 4
…
}
注释1、2:通过 parcelForJavaObject()
把 Java层的Parce -> Natve层的Parcel,data是参数数据,reply是结果数据
注释3:把 java层的 ActivityManagerService的 BinderProxy
转换成 Native层的 BpBinder
注释4:调用 BpBinder.transact()
到这里我就不往下说了,BpBinder会调用 IPCThreadState.transact()
、writeData()
、talkWithDriver()
、waitForResponse()
等方法去深入到 Kernel层的Binder,具体请看: Android Binder原理(三)系统服务的注册过程,里面写了一个系统服务注册到ServiceManager的过程,其中就有上述接下来的过程。
这样我们的Binder数据就从客户端进程传出去了。
2.3 ActivityManagerService接收数据
如果一个支持Binder通信的进程被创建后,它会开启一条线程加入到Binder线程池中,并通过 joinThreadPool()
开启死循环,读 Binder驱动中的 BR_TRANSACTION
(因为客户端进程传入的是 BC_TRANSACTION
)命令,具体可以看 《Android进阶解密》第三章 应用程序进程的创建。
// IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
…
do {
…
result = getAndExecuteCommand();
…
} while (result != -ECONNREFUSED && result != -EBADF);
…
talkWithDriver(false);
}
可以看到在死循环中不断调用 getAndExecuteCommand()
:
status_t IPCThreadState::getAndExecuteCommand()
{
…
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
…
result = executeCommand(cmd);
…
}
return result;
}
// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
//和Binder驱动通信的结构体
binder_write_read bwr; //1
//mIn是否有可读的数据,接收的数据存储在mIn
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();//2
//这时doReceive的值为true
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();//3
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
…
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(ANDROID)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//4
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
…
} while (err == -EINTR);
…
return err;
}
talkWithDriver()
就是通过 ioctl
读取有没有想要的BR数据,有就响应,调用 executeCommand()
:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
…
case BR_TRANSACTION:
{
binder_transaction_data tr; // 1
result = mIn.read(&tr, sizeof(tr)); // 2
…
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); // 3
…
Parcel reply;
status_t error;
if (tr.target.ptr) {
if (…) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags); // 4
}
} …
…
}
break;
…
return result;
}
这里只要截取 BR_TRANSACTION
,因为客户端进程发的是 BC_TRANSATION
注释1:创建 binder_transaction_data
结构体的对象tr,它是IPCThread专用的 Parcel包, 在客户端进程的IPCThreadState调用transact时也是用这个类型
注释2:mIn是Binder驱动的读到的Parcel数据,通过 read()方法把这些数据写入到 tr中
注释3:通过写好的数据重新构造一个 Parcel包。(把它修改成AMS用的包)
注释4:调用 BBinder.transact()
,这里的 BBinder是指 ActivityManagerService在Service端的对象,也就是自己。最后会调用自己的 onTransact()
,会调用父类也就是 IActivityManager.onTransact()
在 IActivityManager
对 onTransact应该是对 TRANSACTION_bindService()
case处理,虽然我们没有 IActivityManager这个类,但是我们通过 IUserManager
文件,可以仿写一份 IActivityManager的代码:
// 跟IActivityManager.Stub.Proxy类一样, 根据 IUserManager 仿写 IActivityManager.Stub.onTransact(),
// 代码参照开篇Blog,即Android7.0 的Binder返回的处理
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
…
case TRANSACTION_bindService: {
data.enforceInterface(descriptor);
IBinder b = data.readStrongBinder(); // 1
IApplicationThread app = ApplicationThreadNative.asInterface(b);
IBinder token = data.readStrongBinder();
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
b = data.readStrongBinder();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
int fl = data.readInt();
int userId = data.readInt();
int res = bindService(app, token, service, resolvedType, conn, fl, userId); // 5
reply.writeNoException();
reply.writeInt(res);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
在拿到 natvie层的Pacel包后,进行拆包。
注释1-2前:通过readString() 、readInt()、 readStrongBinder()
拆包,怎么装包的就怎么拆包
注释2:执行 ActivityManagerService.bindService()
,正式开启 AMS之旅。
我们来看看解包的一个方法 readStrongBinder()
,它和装包的 writeStrongBinder()
对应:
// Parcel.cpp
status_t Parcel::readStrongBinder(sp* val) const
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
、 readStrongBinder()
拆包,怎么装包的就怎么拆包
注释2:执行 ActivityManagerService.bindService()
,正式开启 AMS之旅。
我们来看看解包的一个方法 readStrongBinder()
,它和装包的 writeStrongBinder()
对应:
// Parcel.cpp
status_t Parcel::readStrongBinder(sp* val) const
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-OqkeG3ch-1715840233117)]
[外链图片转存中…(img-YQ7IMtVa-1715840233118)]
[外链图片转存中…(img-vxfDF9HA-1715840233118)]
[外链图片转存中…(img-ZTEP7Y31-1715840233119)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!