Android Binder分析五:Java service的获取和调用

时间:2021-12-25 21:06:24

前面介绍过注册Java Service的流程,这一章我们来看应用程序如何调用Java Service的接口。

Java Service的获取

在Java Service当中,会经常使用到AIDL工具,AIDL在google官方文档的解释是:"AIDL (Android Interface Definition Language) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC)"。即AIDL是一种接口描述语言,用于定义client和service共同认可的接口。听起来比较绕口,直接来看IWifiManger.aidl的大致内容:

interface IWifiManager
{
    List<WifiConfiguration> getConfiguredNetworks();

    int addOrUpdateNetwork(in WifiConfiguration config);

    boolean removeNetwork(int netId);

    boolean enableNetwork(int netId, boolean disableOthers);

    boolean disableNetwork(int netId);

    boolean pingSupplicant();

    void startScan(in WorkSource ws);

    List<ScanResult> getScanResults(String callingPackage);

    void disconnect();

    void reconnect();

    void reassociate();

这里定义了一系列的函数接口,在AIDL中除了支持Java原始类型数据(int、long、char、boolean等),还支持String、CharSequence、list和map。进过AIDL工具的转换,就可以将上面的aidl文件生成一个Java文件,其内容大致如下:

public interface IWifiManager extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements
            android.net.wifi.IWifiManager {
        private static final java.lang.String DESCRIPTOR = "android.net.wifi.IWifiManager";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static android.net.wifi.IWifiManager asInterface(
                android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = (android.os.IInterface) obj
                    .queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof android.net.wifi.IWifiManager))) {
                return ((android.net.wifi.IWifiManager) iin);
            }
            return new android.net.wifi.IWifiManager.Stub.Proxy(obj);
        }

        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) {
        
            }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements android.net.wifi.IWifiManager {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }
        }

IWifiManager.java中主要包含三个类:IWifiManager类、IWifiManager.Stub类、IWifiManager.Stub.Proxy类,WifiSerive就是继承于IWifiManager.Stub类。前面我们已经看过它的关系了,下面来看一般获取WifiService的方法:

                    IBinder b = ServiceManager.getService(WIFI_SERVICE);
                    IWifiManager service = IWifiManager.Stub.asInterface(b);
                    return new WifiManager(ctx.getOuterContext(), service);

这里调用ServiceManager的getService方法,WIFI_SERVICE就是"wifi"字串:

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

sCache用于缓存所有使用过的Java Service,它有ActivityManagerService在fork进程的时候拷贝进来,我们以后分析到AMS的时候再来看sCache,这里先假设sCache并没有我们想要的"wifi" service。然后调用getIServiceManager()的getService方法。前面分析过getIServiceManager()其实最后就是返回ServiceManagerProxy(BinderProxy),所以这里调用ServiceManagerProxy的getService方法:

    public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

首先获取两个Parcel对象,然后向data中写入Strict mode和"android.os.IServiceManager",然后再写入想要获取的service名字,即“wifi”。再调用mRemote.transact方法,这里的实现在android_util_Binder.cpp中,我们前面一章分析过,这里直接调用BpBinder(0)的transact方法,将GET_SERVICE_TRANSACTION命令发往binder驱动。我们来看Java层如何从Parcel中读取想要的Servcie:

    public final IBinder readStrongBinder() {
        return nativeReadStrongBinder(mNativePtr);
    }

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

我们前面在分析Native Service的获取时曾经说过binder驱动首先判断ref->node->proc == target_proc,即注册的进程和现在获取MediaPlayerService的进程是否是同一个,如果是,则改写fp->type为BINDER_TYPE_BINDER,并设置fp->binder为binder->getWeakRefs(),fp->cookie等于binder->local本身。如果不是在同一个进程(这也是大多数case的状况),则首先调用binder_get_ref_for_node为获取MediaPlayerService的进程分配一个新的binder_ref结构,这里的binder id值可能不是之前注册的binder id值了(因为不在同一个进程,desc是往上增长的),然后设置fp->handle为新的desc值。首先来看Native层的Parcel的readStrongBinder方法:

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

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 = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}

这里分两种情况,一是注册WifiService的进程和获取WifiService的进程是同一个时(这个比较经常,因为注册WifiService是在systemserver当中,systemserver会注册很多其它的Service,这些Service会互相调用)。这时type就是BINDER_TYPE_BINDER,然后通过static_cast将cookie处保存的指针直接转换为前面注册的JavaBBinder;二是注册WifiSerivce的进程和获取WifiService的进程不是同一个时,这里调用getStrongProxyForHandle重新返回一个BpBinder(handle id)。回到上面的android_os_Parcel_readStrongBinder方法,这里再调用javaObjectForIBinder对IBinder对象做一层封装:

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {

    }

    AutoMutex _l(mProxyLock);

    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }

    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);

        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));

        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }

    return object;
}

前一章里面分析过这个函数,这里会构造一个BinderProxy对象,并将当前的IBinder(可能是JavaBBinder,也可能是BpBinder)与BinderProxy绑定起来。然后将BinderProxy对象返回给获取Service的进程。接着调用IWifiManager service = IWifiManager.Stub.asInterface(b),它的实现如下:

        public static android.net.wifi.IWifiManager asInterface(
                android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = (android.os.IInterface) obj
                    .queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof android.net.wifi.IWifiManager))) {
                return ((android.net.wifi.IWifiManager) iin);
            }
            return new android.net.wifi.IWifiManager.Stub.Proxy(obj);
        }
这里的obj是BinderProxy对象,它的queryLocalInterface默认返回NULL,所以这里会先构造一个IWifiManager.Stub.Proxy并返回。最后通过IWifiManager.Stub.Proxy构造一个WifiManager对象给应用层使用。


Java Service的调用

我们来看一下WifiManager中一个简单的API使用:
    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
        try {
            mService.setWifiApEnabled(wifiConfig, enabled);
            return true;
        } catch (RemoteException e) {
            return false;
        }
    }

这里的mService就是上面构造的IWifiManager.Stub.Proxy对象,来看它的setWifiApEnabled方法:
            public boolean setWifiApEnabled(
                    android.net.wifi.WifiConfiguration wifiConfig,
                    boolean enable) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((wifiConfig != null)) {
                        _data.writeInt(1);
                        wifiConfig.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    _data.writeInt(((enable) ? (1) : (0)));
                    mRemote.transact(Stub.TRANSACTION_setWifiApEnabled, _data,
                            _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

首先还是获取两个Parcel对象,一个用于存储发送到WifiService的数据;一个用于获取WifiService的回复。并向data中写入strict mode和"android.net.wifi.IWifiManager",再写入两个参数。最后调用mRemote.transact方法。我们知道这里的mRemote就是前面构造的BinderProxy对象,所以来看它的transact方法,它的实现在android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    if (dataObj == NULL) {

    }

    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }

    IBinder* target = (IBinder*)
        env->GetIntField(obj, gBinderProxyOffsets.mObject);
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }

    status_t err = target->transact(code, *data, reply, flags);

    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }

    signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
    return JNI_FALSE;
}

这里也要分两种情况讨论,一种是在同一个进程中,这里的target就是JavaBBinder;如果在不同进程中,这里的target就是BpBinder。首先来看在同一个进程的情况,调用JavaBBinder的transact方法,因为JavaBBinder是继承于BBinder,所以直接到BBinder的transact方法中:
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

直接调用onTransact方法,当然这里的onTransact方法是JavaBBinder重写后的。当不同同一个进程中调用时,target就是BpBinder,所以调用BpBinder的transact方法,最后通过ioctrl发送命令给注册binder驱动中的JavaBBinder(WifiService的包装),同样还是会调用到JavaBBinder的onTransact方法,只是多了一个跨进程的数据传递过程。
    virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {
        JNIEnv* env = javavm_to_jnienv(mVM);

        IPCThreadState* thread_state = IPCThreadState::self();
        const int strict_policy_before = thread_state->getStrictModePolicy();
        thread_state->setLastTransactionBinderFlags(flags);

        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, (int32_t)&data, (int32_t)reply, flags);
        jthrowable excep = env->ExceptionOccurred();

        const int strict_policy_after = thread_state->getStrictModePolicy();
        if (strict_policy_after != strict_policy_before) {
            thread_state->setStrictModePolicy(strict_policy_before);
            set_dalvik_blockguard_policy(env, strict_policy_before);
        }

        jthrowable excep2 = env->ExceptionOccurred();
        if (excep2) {
            report_exception(env, excep2,
                "*** Uncaught exception in onBinderStrictModePolicyChange");
            /* clean up JNI local ref -- we don't return to Java code */
            env->DeleteLocalRef(excep2);
        }

        if (code == SYSPROPS_TRANSACTION) {
            BBinder::onTransact(code, data, reply, flags);
        }

        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
    }

这里主要就是调用Binder.java的execTransact来处理请求:
    private boolean execTransact(int code, int dataObj, int replyObj,
            int flags) {
        Parcel data = Parcel.obtain(dataObj);
        Parcel reply = Parcel.obtain(replyObj);
        boolean res;
        try {
            res = onTransact(code, data, reply, flags);
        } catch (RemoteException e) {
            if ((flags & FLAG_ONEWAY) != 0) {
                Log.w(TAG, "Binder call failed.", e);
            }
            reply.setDataPosition(0);
            reply.writeException(e);
            res = true;
        } catch (RuntimeException e) {
            if ((flags & FLAG_ONEWAY) != 0) {
                Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
            }
            reply.setDataPosition(0);
            reply.writeException(e);
            res = true;
        } catch (OutOfMemoryError e) {
            Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);
            RuntimeException re = new RuntimeException("Out of memory", e);
            reply.setDataPosition(0);
            reply.writeException(re);
            res = true;
        }
        reply.recycle();
        data.recycle();
        return res;
    }
}

这里直接调用WIfiService的onTransact方法,它的实现在IWifiManager.Stub中:
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
            switch (code) {

            case TRANSACTION_setWifiApEnabled: {
                data.enforceInterface(DESCRIPTOR);
                android.net.wifi.WifiConfiguration _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = android.net.wifi.WifiConfiguration.CREATOR
                            .createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                boolean _arg1;
                _arg1 = (0 != data.readInt());
                boolean _result = this.setWifiApEnabled(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(((_result) ? (1) : (0)));
                return true;
            }

首先从Parcel中读出WifiConfiguration和enable两个参数,然后调用WifiServcie的setWifiApEnabled方法,并把执行结果写入到reply中。如果不在同一个进程中调用,最后通过IPCThreadState的sendReply方法将结果返回给调用者。到这里,一次Java Servcie的调用就完成了。