首先感谢:
从AILD与bindService谈Binder进程间通信原理(上) 解答了我很多疑惑, 但由于上述文章的源码是7.0的,Java框架层没有用AIDL,所以我想根据新的源码(8.0)来理解Binder的知识。
前几天在学习一些Binder机制(较浅)后,我就在趁热打铁看看AIDL的一些东西,在学习的时候发现了几点疑问,并且网上鲜有解答:
-
ServiceManager
管理的是系统服务,那我们自定义的Service会注册到ServiceManager中吗? - 为什么AIDL中的跨进程下asInterface()会返回
BinderProxy
?我们在Service的启动流程没有留意到这个类呀?
不过最后我一些地方还是有些模糊,如果大神能有幸阅读我的文章,请麻烦指出我文中的错误!我定查阅改正。
1.关于系统Service和自定义Service的区别
这里是 bindService在应用层 - framwork层的绑定流程,源码基于8.0:Service的startService和bindService源码流程 或者阅读《Android进阶解密》第四章
这里是关于系统服务和ServiceManager在基于Binder角度 注册、获取、使用上的流程,源码基于9.0,也是皇叔写的:Binder原理
可以大概总结出他们的区别:
- 系统Service
是指在 SystemServer进程开启后,通过startBootstrapServices()
、startCoreServices()
、startOtherServices()
所开启的服务,他们显示地通过add_service()
注册在了ServiceManager
中。
之后客户端进程想要使用系统Service,需要通过 ServiceManager的进程来查看是否有目标Service,然后再来获取和使用 - 自定义Service
通过startService()
和bindService()
两种方式开启,在framwork框架层中没有发现流程中使用add_service方法(甚至都没出现ServiceManager)。
↑ 这就看出无论自定义Service最后在不在ServiceManager中,Android本身是不希望我们通过ServiceManager的途径去获取使用自定义Service的。
上述第二条的结论,原因是什么?我不是很清楚,但是基于结论来看:
只要一个进程持有另一进程的BinderProxy类,那我还去找 ServiceManager干什么,这不更加省事吗?
所以,在自定义的流程中把ServiceManager忽略掉,我们就不用考虑Service到底有没有注册在ServiceManager中了。
2. 从AIDL上看Binder
AIDL本质上是在Java层对Binder进行了封装。所以Android8.0前后AMS是否使用了AIDL,本质都是使用Binder + 代理模式,只是说使用了 AIDL通过编译时生成代码,节省了一些代码的编写,提高了开发效率。
那么我们就从编译时产生的代码开始,来看看Binder的运作机制,这里使用的例子是:使用AIDL来进行进程间通信,就是一个 Service远程服务 + User类 + IUserManager代理类
2.1 用于进程传输的Stub类
在编译文件产生的 IUserManager中,它是一个接口类,同时它有一个静态内部类 Stub
:
// IUserManager.java
// 0
public static abstract class Stub extends android.os.Binder implements com.rikkatheworld.aidl_demo.IUserManager {
private static final java.lang.String DESCRIPTOR = "com.rikkatheworld.aidl_demo.IUserManager";
// 1
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 2
public static com.rikkatheworld.aidl_demo.IUserManager asInterface(android.os.IBinder obj) {
...
}
// 3
@Override
public android.os.IBinder asBinder() {
return this;
}
// 4
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
...
}
// 5
private static class Proxy implements com.rikkatheworld.aidl_demo.IUserManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
...
// 6
@Override
public com.rikkatheworld.aidl_demo.User getUser(java.lang.String name) throws android.os.RemoteException {
....
}
}
}
Stub类分成两个部分,一个是自己本身的成员方法,另一个是Proxy类,先来看看这些成员。
(1)自身部分
- 注释0
Stub类继承自Binder
,说明这个类是用于进程间传输的。 - 注释1
Stub()
构造方法,把自身和标记自身的descriptor传入,后者用于表明身份 - 注释2
asInterface(obj)
静态方法, 处理ActivityManagerService丢给我们的 IBinder,将它转换成 客户端进程想要的类。 - 注释3:
asBinder()
用于Binder传输的过程,需要转换自身的类型,Stub(A进程)->IBinder(Binder)->Stub(B进程),就用到这个方法,这个例子非常粗糙,可能也有问题,但是这个方法是辅助用的,我们不需要对这个方法深入理解。 - 注释4 :
onTransact()
重写父类的 onTrancsact,这个方法是客户端进程在使用Binder进行数据传输时需要用到的数据。
(2)Proxy代理类
- 注释5
静态内部类,实现了 IUserManager接口
内部定义了一个 IBinder类型的 mRemote对象 - 注释6
实现方法,如果客户端进程要跨进程调用Server端的方法,就要通过调用这些方法。
我们看看客户端进程是怎么使用这个类的:
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 1
IUserManager userManager = IUserManager.Stub.asInterface(service);
try {
User user = userManager.getUser("Rikka");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
AIDL的客户端进程,在 onServiceConnected()
中拿到 AMS传过来的 service,通过 asInterface()
转化成 IUserManager,然后调用它的方法,就能完成跨进程的方法调用了。
我们来看看 asInterface()
具体实现:
// IUserManager.java
...
public static com.rikkatheworld.aidl_demo.IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.rikkatheworld.aidl_demo.IUserManager))) {
return ((com.rikkatheworld.aidl_demo.IUserManager) iin);
}
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
。
2.2 BindService 客户端进程传出流程
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<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@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<IBinder> 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<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& 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<IBinder>& /*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<IBinder>* val) const
{
status_t status = readNullableStrongBinder(val);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return status;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflatten_binder(ProcessState::self(), *this, val);
}
readStrongBinder()调用了 readNullableStrongBinder()
,它里面调用了 unflatten_binder()
:
// Parcel.cpp
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle); // 1
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
我们在客户端进程传入进来flat的是 BINDER_TYPE_BINDER
, 但是我跟你讲,这里拿到的是 BINDER_TYPE_HANDLE
,因为
- 如果是非跨进程调用
数据Parcel包在kernel层不会做修改 - 如果是跨进程调用
kernel层的binder_transaction()
会修改这个值,即BINDER_TYPE_BINDER
->BINDER_TYPE_HANDLE
所以这里会在注释1中得到一个 BpBinder
,然后返回。
也就是说 readStrongBinder(Parcel)
可以拿到 parcel包里面的 的Binder数据并转化为 BpBinder, 然后把BpBinder通过 Parcel.javaObjectForIBinder()
转换成 BinderProxy
。在Android7.0可以找到这个转换,8.0后我突然找不到了…不知道为什么。以后找机会再查查吧。
到这里,就已经明了了,客户端进程的 Binder 到了 服务端进程后 会包装成 BinderProxy。
这句话也可以换成:
任意一个进程的IBinder 通过 Binder机制 到达了另外一个进程后,就会包装成一个 BinderProxy。
这就回到了我最开始的第二点疑问,通过Service -> AMS -> MainActivity.onServiceConnection(IBinder) 中的 IBinder是一个BindProxy类。
3. 总结
从一开始我的两个问题,到现在也算是解决了。
自定义Service并不需要通过 addService()
来加入到 ServiceManager,因为它只要别的进程能够持有它的BinderProxy,就可以调用它的方法。
其次 Binder在跨进程后会转换成 BindProxy,这也是为什么AIDL中能够拿到 Proxy类。
至此,通过AIDL来看Binder原理也就写完了。但是还没有结束,因为我上面应该是由一些还没有具体解决的点,我列一下:
-
IActivityManager
的代码到底时怎么样的? - Android7.0 的
readStrongBinder()
显示的用了javaObjectForIBinder()
把 unflatten_binder得到 BpBinder转换成了 BinderProxy,但是Andorid8.0我却没有看到这样的代码,到了BpBinder就好了…不知道是不是我看漏了,反正查了半天没查到…
如果有大牛看到希望可以解答我的疑问。