通过 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 descrip Android开源项目:ali1024.coding.net/public/P7/Android/git tor) {
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 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 ! 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》开源 = 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;
最后
一线互联网Android面试题含详解(初级到高级专题)
这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率
如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。
最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;
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;
最后
一线互联网Android面试题含详解(初级到高级专题)
这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率
[外链图片转存中…(img-5CnY23p5-1649944953211)]
如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。
最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;