【内核研究】获取Binder对象

以上手工编写Binder服务端和客户端的过程存在两个重要问题。

第一,客户端如何获得服务端的Binder对象引用。

第二,客户端和服务端必须事先约定好两件事情。

服务端函数的参数在包裹中的顺序。

服务端不同函数的int型标识。

关于第一个问题,请思考为什么要用Binder。答案很简单,即为了提供一个全局服务,所谓的"全局",是指系统中的任何应用程序都可以访问。很明显,这是一个操作系统应该提供的最基本的功能之一,Android的工程师自然也是这么认为的,因此,他们提供了一个更傻瓜的解决方法,那就是Service。它是Android应用程序四个基本程序片段(Component)之一,四个基本片段包括Activity、Service、Content Provier、Receiver。

无论是否使用Service类,都必须要解决以上两个重要问题。因此,下面先介绍如何解决第一个问题。


事实上,对于有创造力的程序员来讲,可以完全不使用Service类,而仅仅基于Binder类编写服务程序,但只是一部分。具体来讲,可以仅使用Binder类扩展系统服务,而对于客户端服务则必须基于Service类来编写。所谓的系统服务是指可以使用getSystemService()方法获取的服务,所谓的客户端服务是指应用程序提供的自定义服务。

Service和Binder的关系。

那么,Service类是如何解决本节开头所提出的两个重要问题的呢?

首先,AmS提供了startService()函数用于启动客户服务,而对于客户端来讲,可以使用以下两个函数来和一个服务建立连接,其原型在android.app. ContextImpl类中。

    @Override
    public ComponentName startService(Intent service) {
        try {
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()));
            if (cn != null && cn.getPackageName().equals("!")) {
                throw new SecurityException(
                        "Not allowed to start service " + service
                        + " without permission " + cn.getClassName());
            }
            return cn;
        } catch (RemoteException e) {
            return null;
        }
    }

该函数用于启动intent指定的服务,而启动后,客户端暂时还没有服务端的Binder引用,因此,暂时还不能调用任何服务功能。

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        IServiceConnection sd;
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        try {
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(),
                service, service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags);
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            return false;
        }
    }

该函数用于绑定一个服务,这就是第一个重要问题的关键所在。其中第二个参数是一个interface类,该interface的定义如以下代码所示:

/**
 * Interface for monitoring the state of an application service.  See
 * {@link android.app.Service} and
 * {@link Context#bindService Context.bindService()} for more information.
 * <p>Like many callbacks from the system, the methods on this class are called
 * from the main thread of your process.
 */
public interface ServiceConnection {
    /**
     * Called when a connection to the Service has been established, with
     * the {@link android.os.IBinder} of the communication channel to the
     * Service.
     *
     * @param name The concrete component name of the service that has
     * been connected.
     *
     * @param service The IBinder of the Service's communication channel,
     * which you can now make calls on.
     */
    public void onServiceConnected(ComponentName name, IBinder service);

    /**
     * Called when a connection to the Service has been lost.  This typically
     * happens when the process hosting the service has crashed or been killed.
     * This does <em>not</em> remove the ServiceConnection itself -- this
     * binding to the service will remain active, and you will receive a call
     * to {@link #onServiceConnected} when the Service is next running.
     *
     * @param name The concrete component name of the service whose
     * connection has been lost.
     */
    public void onServiceDisconnected(ComponentName name);
}

请注意该interface中的onServiceConnected()方法的第二个变量Service。当客户端请求AmS启动某个Service后,该Service如果正常启动,那么AmS就会远程调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含Service的Binder引用,然后在ApplicationThread中会回调bindService中的conn接口。因此,在客户端中,可以在onServiceConnected()方法中将其参数Service保存为一个全局变量,从而在客户端的任何地方都可以随时调用该远程服务。这就解决了第一个重要问题,即客户端如何获取远程服务的Binder引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值