作者:李尚
ServiceManager其实主要的面向对象是系统服务,大部分系统服务都是由SystemServer进程总添加到ServiceManager中去的,在通过ServiceManager添加服务的时候,是有些权限校验的,源码如下:
int svc_can_register(unsigned uid, uint16_t *name)
{
unsigned n;
// 谁有权限add_service 0进程,或者 AID_SYSTEM进程
if ((uid == 0) || (uid == AID_SYSTEM))
return 1;
for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
return 1;
return 0;
}
可以看到 (uid == 0) 或者 (uid == AID_SYSTEM)的进程都是可以添加服务的,uid=0,代表root用户,而uid=AID_SYSTEM,代表系统用户 。或者是一些特殊的配置进程。SystemServer进程在被Zygote创建的时候,就被分配了UID 是AID_SYSTEM(1000),
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
Android每个APP的UID,都是不同的,用了Linux的UID那一套,但是没完全沿用,这里不探讨,总之,普通的进程是没有权限注册到ServiceManager中的,那么APP平时通过bindService启动的服务怎么注册于查询的呢?接管这个任务的就是SystemServer的ActivityManagerService。
bindService比startService多了一套Binder通信,其余的流程基本相同,而startService的流程,同startActivity差不多,四大组件的启动流程这里不做分析点,主要看bindService中C/S通信的建立流程,在这个流程里面,APP与服务端互为C/S的特性更明显,在APP开发的时候,binder服务是通过Service来启动的。Service的启动方式有两种startService,与bindService,这里只考虑后者,另外启动的binder服务也分为两种情况:第一种,client同server位于同一进程,可以看做内部服务,第二种,Client与Server跨进程,即使是位于同一个APP,第一桶可以不用AIDL来编写,但是第二种必须通过AIDL实现跨进程通信,看一个最简单的AIDL例子,首先在定义一个aidl接口:
IMyAidlInterface.aidl
interface IMyAidlInterface { void communicate(int count); }
IMyAidlInterface.aidl定义了通信的借口,通过build之后,构建工具会自动为IMyAidlInterface.aidl生成一些辅助类,这些辅助类主要作用是生成Binder通信协议框架,必须保证两方通信需要指令相同,才能解析通信内容。天王盖地虎,宝塔镇河妖。Java层Binder的对应关系Binder与BinderProxy从这里可以看出,binder采用了代理模式 stub与proxy对应,使用aidl实现的服务时候,Client如果想要获得Binder实体的代理可以通过asInterface来处理,比如如果在同一进程就是实体,不在就新建代理对象
public interface IMyAidlInterface extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.snail.labaffinity.IMyAidlInterface {
private static final java.lang.String DESCRIPTOR = "com.snail.labaffinity.IMyAidlInterface";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.snail.labaffinity.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.snail.labaffinity.IMyAidlInterface))) {
return ((com.snail.labaffinity.IMyAidlInterface) iin);
}
return new com.snail.labaffinity.IMyAidlInterface.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_communicate: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.communicate(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.snail.labaffinity.IMyAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void communicate(int count) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(count);
mRemote.transact(Stub.TRANSACTION_communicate, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_communicate = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void communicate(int count) throws android.os.RemoteException;
}
启动Binder服务端封装Service,之所以成为封装Service,是因为Service对于Binder实体的最大作用是个作为新建服务的入口:
public class AidlService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new BBinderService();
}
public class BBinderService extends IMyAidlInterface.Stub {
@Override
public void communicate(int count) throws RemoteException {
}
}
}
而启动的入口:
public class MainActivity extends AppCompatActivity {
...
void bind(){
Intent intent = createExplicitFromImplicitIntent(MainActivity.this, new Intent("com.snail.labaffinity.service.AidlService"));
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}, Context.BIND_AUTO_CREATE);
}
}
以上四个部分就组成了AIDL跨进程服务的基本组件,现在从ActivitybindService入口开始分析:bindService大部分的流程与startActivity类似,其实都是通过AMS启动组件,这里只将一些不同的地方,Activity启动只需要Intent就可以了,而Service的bind需要一个ServiceConnection对象,这个对象其实是为了AMS端在启动Service后回调用的,ServiceConnection是个接口,其实例在ContextImpl的:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags & BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
mPackageInfo是一个LoadApk类,通过它的getServiceDispatcher获得一个IServiceConnection对象,这个对象一个Binder实体,看一下具体原理
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
在LoadApk中IServiceConnection对象是通过context键值来存储ServiceDispatcher对象,而ServiceDispatcher对象内存会有个InnerConnection对象,该对象就是getServiceDispatcher的返回对象。因此bindServiceCommon最终调用 ActivityManagerNative.getDefault().bindService(x,x,x,x,x sd, x, x, x) 的时候,传递的参数sd其实就是一个InnerConnection对象,这是个Binder实体。但是,Binder.java中的Binder只是对native层BBinder的一个简单封装,真正的实例化还是通过JNI到native层去创建一个JavaBBinderHolder对象,并初始化gBinderOffsets,让其能映射Java层Binder对象,而JavaBBinderHolder中又可以实例化BBinder的实例JavaBBinder,不过BBinder的实例化时机并不在这里,而是在Parcel对象writeStrongBinder的时候,
static struct bindernative_offsets_t
{
// Class state.
jclass mClass;
jmethodID mExecTransact;
// Object state.
jfieldID mObject;
} gBinderOffsets;
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
jbh->incStrong((void*)android_os_Binder_init);
env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
继续往下看bindService,会调用到ActivityManagerProxy的bindService
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeStrongBinder(token);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
data.recycle();
reply.recycle();
return res;
}
利用Parcel的writeStrongBinder会将Binder实体写入到Parcel中去,这里首先看一下 Parcel data = Parcel.obtain();在java层Parcel只是一个容器,具体Parcel相关的操作都在Native层
static jint android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
return reinterpret_cast<jint>(parcel);
}
这里的返回值,其实就是Parcel对象的地址,被赋值给了Parcel.java的mNativePtr成员变量,方便Native调用,接着看writeStrongBinder的实现,其实就是调用Parcel.cpp中的对应方法,通过flatten_binder将Binder实体对象打扁,创建flat_binder_object写入Parcel中,
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint 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);
}
}
}
ibinderForJavaObject主要为Java层Binder实例化native binder对象:
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
}
return NULL;
}
如果BBinder还没实例化,要通过JavaBBinderHolder的get函数实例化一个BBinder对象,这里就是JavaBBinder对象,综上分析Java层与Native的Binder其对应关系如下:
BBinder对象被Parcel转换成flat_binder_object,经过一次拷贝写入目标进程,并执行BINDER_TYPE_BINDER与BINDER_TYPE_HANDLE的转换,如下:
static void
binder_transaction(struct binder_proc *proc, struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
...
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {..
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {..
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
} else {
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
fp->handle = new_ref->desc;
}
} break;
}
在内核中,bindService中的InnerConnection会由BINDER_TYPE_BINDER转换成BINDER_TYPE_HANDLE,之后,AMS线程被唤醒后,执行后面的流程,在前文分析Parcel数据转换的时候,在Binder线程被唤醒继续执行的时候,会将数据映射到一个natvie Parcel对象中
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
switch (cmd) {
..
// read到了数据请求,这里是需要处理的逻辑 ,处理完毕,
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
Parcel buffer;
<!--关键点1 -->
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this);
...
<!--关键点2 -->
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
..
}
}
相关阅读:
https://www.163yun.com/gift
本文来自网易实践者社区,经作者李尚授权发布。