Java层服务注册到 ServiceManager

前面提到 AMS 在启动后会将自身作为Context.ACTIVITY_SERVICE的服务注册到 ServiceManager,同事 ServiceManager 的一大功能就是进行服务的注册。下面就以 AMS 注册到 ServiceManager 为例,探讨注册服务的过程。

//.../frameworks//base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setSystemProcess(){
    ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
    ...
}
//.../frameworks/base/core/java/android/os/ServiceManager.java
//主要让我疑惑的是 allowIsolated 这个参数
//@param allowIsolated set to true to allow isolated sandboxed processed to access this service
//乍看是说 ture 表示允许隔离的沙盒进程来访问这个服务,暂时看不懂喔
public static void addService(String name, IBinder service, boolean allowIsolated){
    getIServiceManager().addService(name, service, allowIsolated);
}

private static IServiceManager getIServiceManager(){
    //采用单例模式
    if(sServiceManager != null){
        return sServiceManaer;
    }    
    //find the service manager
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}

关键就是 ServiceManagerNative.asInterface(BinderInternal.getContextObject())这个方法了

拆分,先看 BinderInternal.getContextObject()再来看 ServiceManagerNative.asinterface();

//.../frameworks//base/core/java/com/android/internal/os/BinderInternal.java
public static final native IBinder getContextObject();

看到这个方法是 native 实现,

//.../frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
   sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
   return javaObjectForIBinder(env, b);
}

ProcessState 采用了单例,保存了进程的上下文信息

//.../frameworks//native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}

ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , ...
{
        ...
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
      ...

//关于打开驱动做了什么,后面有空单独分析
static int open_driver()
{
    int fd = open("/dev/binder", O_RDWR);
}

关于 ProcessState::getStrongProxyForHandle(0)在defaultServiceManager()@IServiceManager.cpp中介绍过,得到一个new BpBinder(0)
于是

//...frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
    等价于
    return javaObjectForIBinder(env, new BpBinder(0));
}

//先看这个方法,是javaObjectForIBinder()的前置
const char* const kBinderPrxyPathName  = "android/os/BinderProxy";
static int int_register_android_os_BinderProxy(JNIEnv* env){
    ...
    clazz = FindClassOrDie(env, kBinderProxyPathName);
    //代表android.os.BinderProxy 这个类
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    //代表其构造函数 BinderProxy()
    gBinderProxyOffsets.mConstructor = GetMethodIdOrDie(env, clazz, "<init>", "()V");
    //字段 long mObject
    gBinderProxyOffsets.mObject = GetFieldIdOrDie(env, clazz, "mObject", "J");
    //字段 WeakReferenct mSelf
    gBinderProxyOffsets.mSelt = GetFieldOrDie(env, clazz, "mSelf", "Ljava/lang/ref/WeakReference;");
    ...
    ...
}

//然后看,注意这里的val 是一个 BpBinder,并且此时 handle 是0
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val){
    ...
    //从上可以知道这里实例化了一个android.os.BinderProxy 对象
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    //这里将这个 BpBinder 的句柄保存在这个 BinderProxy 对象的mObject 成员变量中
    env->SetLongField(object, gBinderProxyOffets.mObject,(jlong)val.get());
    ...
    //返回的是 BinderProxy 对象
    return object;
}

可以看到BinderInternal.getContextObject()得到了一个android.os.BinderProxy 对象,并且其内部持有一个BpBinder(0)的引用(handle 为0代表指向 service manager)。

ServiceManagerNative.asInterface(BinderInternal.getContextObject());
登记于
ServiceManagerNative.asInterface(BinderProxy(持有BpBinder(0)的引用))
//.../frameworks//base/core/java/android/os/ServiceManagerNative.java
static public IServiceManager asInterface(IBinder obj){
    if(object == null){
        return null;
    }

    //如果寻找的服务在当前进程,会得到 in,就是本地对象否则返回一个本地代理
    IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
    if(in !=null){
        return in;
    }
    return new ServiceManagerProxy(obj);
}

//ServiceManagerNative 的内部类,内部就是保存了这个remote 即 BinderProxy 对象
public ServiceManagerProxy(IBinder remote){
    mRemote = remote
}

现在来看用的地方

public static void addService(String name, IBinder service, boolean allowIsolated){
    getIServiceManager().addService(name, service, allowIsolated);
    等价于
    addService()@ServiceManagerProxy
}
//涉及到了 Parcel 的知识 不知道的需要去补充
public void addService(String name, IBinder service, boolen allowIsolated){
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}

简单说下 Parcel,Parcel 用来打包数据,用链表Parcel 池,在 native 层实例化对象,内部存了一个游标,指向当前指向的数据,因此存储需要对应。

上面用 Parcel 保存了参数,利用 mRemote(BinderProxy) 发送数据远程调用。

//.../frameworks/base/core/java/android/os/Binder.java

final class BinderProxy implements IBinder{
    public boolean transact(int code, Parcel data, parcel reply, int flags){
        return transactNative(code, data, reply, flags);
    }
}

采用 JNI 调用 native 方法,经过 Binder 驱动转发给 service_manager进程,调用者在底层是 IPCThreadState发给驱动(Binder 驱动转发暂时先不讨论,后期再单独写一篇补充)。转发 Binder 请求

在service_manager 说过,内部有一个 loop 接受请求。然后将请求转发给svcmgr_handler方法处理

int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)
{
    ...
    switch(txn->code){
        ...
        //这里就是添加服务了
        case SVG_MGR_ADD_SERVICE:
        s = bio_getString(msg, &len);
        handle = bio_get_Ref(msg);
        allow_isolated = bio_get_unit32(msg)? 1 : 0;
        //添加服务的核心代码
        if(do_add_service()){
            ...
        } 
        break;
    }
}

int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid)
{
    struct svcinfo *si;

    //检查权限
    if (!svc_can_register(s, len, spid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s, len), handle, uid);
        return -1;
    }

    si = find_svc(s, len);
    //服务已经注册过了。就释放相应的服务
    if (si) {
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                 str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
                 str8(s, len), handle, uid);
            return -1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        // 保存所有已经注册的服务
        si->next = svclist;//svclist
        svclist = si;
    }
    //以 BC_ACQUIRE命令。handle 为目标。通过 icotl 发送给 binder 驱动
    binder_acquire(bs, handle);
    //以 BC_REQUEST_DEATH_NOTIFICATION 命令的信息,通过 ioctl 发送给 binder 驱动,主要用于清理内存扥收尾工作
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

注册服务就是将这个服务本身记录到 service_manager 中,这样其他进程需要这个服务时,用name 请求Binder 驱动去转发这个请求给 service manager 后得到目标服务的handle,然后 Binder 驱动将请求转发给真正的目标服务。

按网上的理论,将 Binder驱动理解为路由器,service manager 理解为 DNS的比喻是最恰当的了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,475评论 4 372
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,744评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,101评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,732评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,141评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,049评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,188评论 2 320
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,965评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,716评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,867评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,341评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,663评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,376评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,200评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,990评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,179评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,979评论 2 279

推荐阅读更多精彩内容