Android的服务(Service)(三)Service客户端的绑定与跨进程

继续上篇的分析,接下来是第三个问题”Service与其客户端的绑定如何实现,即跨进程调用问题“

(一)、Service的生命周期

(二)、Service的自动重启问题

(三)、Service与其客户端的绑定如何实现,即跨进程调用问题。

服务于客户端的绑定通过binder来实现的,就是客户端去bind服务。来看看ContextImpl的bindServiceCommon方法

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        }
        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, user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        }
    }

然后会去LoadedApk.java里面会创建用于跨进程连接的binder对象,就是一个ServiceDispatcher的InnerConnection。

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            //这里用一个map将所有的连接记录都保存起来了
            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();
        }
    }
    static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;

        private static class ConnectionInfo {
            IBinder binder;
            IBinder.DeathRecipient deathMonitor;
        }

        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }
            //这个方法就是在ActivityManagerService中执行绑定链接时的方法调用
            //这里的service毫无疑问就是远程对象执行onBind时返回的那个咯
            //所以这里才是服务端和客户端传递一个binder对象的通道,因为这个过程涉及到两个跨进程操作,所以这么设计是必须也是合理的
            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }

        private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();

        ServiceConnection getServiceConnection() {
            return mConnection;
        }

        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

        public void connected(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0));
            } else {
                doConnected(name, service);
            }
        }

        public void death(ComponentName name, IBinder service) {
            .......................
        }
        //实际执行connect
        public void doConnected(ComponentName name, IBinder service) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            synchronized (this) {
                if (mForgotten) {
                    // We unbound before receiving the connection; ignore
                    // any connection received.
                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    // Huh, already have this one.  Oh well!
                    return;
                }

                if (service != null) {
                    // A new service is being connected... set it all up.
                    mDied = false;
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        // This service was dead before we got it...  just
                        // don't do anything with it.
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    // The named service is being disconnected... clean up.
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            // If there was an old service, it is not disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            // If there is a new service, it is now connected.
            // 眼熟了吧,这就是我们在绑定服务后获取远程对象代理的回调咯
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }
        }

        public void doDeath(ComponentName name, IBinder service) {
            mConnection.onServiceDisconnected(name);
        }

        private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command) {
                mName = name;
                mService = service;
                mCommand = command;
            }

            public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }
        }
        private final class DeathMonitor implements IBinder.DeathRecipient
        {
            DeathMonitor(ComponentName name, IBinder service) {
                mName = name;
                mService = service;
            }

            public void binderDied() {
                death(mName, mService);
            }

            final ComponentName mName;
            final IBinder mService;
        }
 }

后面就是bind操作了,前面讲生命周期时已经有提到过的,这里再把那个方法列一下:

        int bindServiceLocked(IApplicationThread caller, IBinder token,
                Intent service, String resolvedType,
                IServiceConnection connection, int flags, int userId) {
            ....................
            ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType,
                        Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
            ....................
            try {
                if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
                    if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
                            + s);
                }
                ...................
                //bindings中添加一起绑定请求,后续requestServiceBindingsLocked()流程中处理绑定接口
                AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
                ....................
                if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                    s.lastActivity = SystemClock.uptimeMillis();
                    //如果携带的标志位中包含自动启动,则进行创建服务的操作,代码可以看前面,如果已经启动了,其实是什么操作也不干的
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                        return 0;
                    }
                }  

                if (s.app != null) {
                    // This could have made the service more important.
                    mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
                    mAm.updateOomAdjLocked(s.app);
                }  

                if (s.app != null && b.intent.received) {
                    // Service is already running, so we can immediately
                    // publish the connection.
                    // 如果服务已经启动并且有绑定过了,直接返回binder对象,这里的conn就是前面提到的InnerConnection的代理,这里看到了connected操作其实是由<pre name="code" class="java">                    // InnerConnection它来完成的
                    try {
                        c.conn.connected(s.name, b.intent.binder);
                    } catch (Exception e) {
                        Slog.w(TAG, "Failure sending service " + s.shortName
                                + " to connection " + c.conn.asBinder()
                                + " (in " + c.binding.client.processName + ")", e);
                    }  

                    // If this is the first app connected back to this binding,
                    // and the service had previously asked to be told when
                    // rebound, then do so.
                    // 从这里可以看出,一般情况下,onBind只会执行一次,除非请求doRebind
                    // 这个标志位是旧的客户端全部unbind之后自动设置上的
                    if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                        requestServiceBindingLocked(s, b.intent, callerFg, true);
                    }
                } else if (!b.intent.requested) {
                    //服务还没有绑定者,则执行后续操作将调用到onBind操作
                    requestServiceBindingLocked(s, b.intent, callerFg, false);
                }  

                getServiceMap(s.userId).ensureNotStartingBackground(s);  

            } finally {
                Binder.restoreCallingIdentity(origId);
            }  

            return 1;
        }  

大家有没有在上面注意一个问题,InnerConnection中并没有unConnected方法,那么解绑的时候又是如何通过这个连接通道执行回调的呢?大家可以看看前面讲的unBind流程中,里面也是没有任何地方会执行到这个操作的,它有的只是服务端的unBind和可能执行onDestory。那么什么时候会执行到ServiceConnection.onServiceDisconnected,事实上只有在远程服务端那个binder死亡才会执行到的。这个就是通过为这个binder对象注册一个IBinder.DeathRecipient,这是binder的死亡通知机制。这里就不讲了。

到这里Android中的服务已经简要的分析了一下,不可能面面俱到也不会全都正确,还请大家多多指教。

时间: 2024-12-31 04:01:18

Android的服务(Service)(三)Service客户端的绑定与跨进程的相关文章

Android SurfaceFlinger服务(三) ----- 本地图层Layer创建

在上一篇文章中,主要分析了Surface的创建过程,对于Layer图层的创建并没有深入跟踪分析.这篇文章将分析Layer图层的创建,并分析handle gbp这两个变量的来源. 在SurfaceFlinger中会根据flags的值创建不同的layer.这里主要以创建普通layer为例进行分析. status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, const String8& name, uin

Android Service 服务(三)—— bindService与remoteService

(转自:http://blog.csdn.net/ithomer/article/details/7366396)   一.bindService简介 bindService是绑定Service服务,执行service服务中的逻辑流程. service通过Context.startService()方法开始,通过Context.stopService()方法停止:也可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己.只要调用一次st

Android 回顾Service之Service基础使用

这两天在回顾Android Service方面的知识,趁着记忆没有消退之前,来总结一下.本文主要讲解Service的基本概念与使用.跨进程调用Service.系统常见Service的使用.所以本文的难度微乎其微,仅适用于想回顾Service知识点的同学,或者还不怎么了解Service的同学,至于Service源码之类的东东,等老夫分析研究之后再来分享. 一.Service基础 我相信只要接触过Android开发的人,都或多或少的了解过Service.Service是什么呢?Service是And

Android 跨进程启动Activity黑屏(白屏)的三种解决方案

原文链接:http://www.cnblogs.com/feidu/p/8057012.html 当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面Lunacher启动一个App时也会出现相同情况,那是因为App冷启动也属于跨进程启动Activity.为什么没会出现这种情况呢?真正元凶就是Android创建进程需要准备很多资源,它是一个耗时的操作. 黑屏(白屏)原因 当A进程启动B进程中的一个Activity时,Android系统会先有zygo

android 跨进程通信

转自:http://www.androidsdn.com/article/show/137 由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service. 其中Activity可以跨进程调用其他应用程序的Activity: Content Pro

Android跨进程通信

由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于android系统中4种应用程序组件:Activity.Content Provider.Broadcast和Service. 其中Activity可以跨进程调用其他应用程序的Activity: Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然也可以对其他

Android四大组件应用系列——使用ContentProvider实现跨进程通讯

一.问题描述 如何在Android中实现不同应用之间的通讯(既跨进程进行调用)?Android提供了多种实现方式,使我们可以实现跨进程访问Activity.通过ContentProvider跨进程访问其他应用的数据.通过Broadcast可以向android系统中所有应用程序发送广播.使用AIDL实现跨进程的Service.下面我们就使用ContentProvider实现跨进程访问数据,并可对数据进行增.删.改.查 二.应用实现 使用ContentProvider实现数据共享,主要是共享应用的S

Android服务之Service(三)关于AIDL进程间通信

转载:http://www.cnblogs.com/zhangdongzi/archive/2012/01/09/2317197.html 一.基础知识 AIDL的作用 在Android平台,每个应用程序App都运行在自己的进程空间.通常一 个进程不能访问另一个进程的内存空间(一个应用不能访问另一个应用),如果想沟通,需要将对象分解成操作系统可以理解的基本单元,Android提供了AIDL来处理. AIDL (Android Interface Definition Language) 是一种I

Android的服务(Service)(一)生命周期

本篇和接下来的几篇我们来浅析一下Android的另外一个非常重要的组件:Service,看到这里我们的脑海里都会涌现出什么词语呢?诸如:无用户交互界面,耗时后台操作,服务(级别)进程,远程调用. 1.看看Service的代码,好干净的感觉,没错,它就定义了一些生命周期的方法以及一些成员,注意这些成员中并没有Window,所以Service是没有用户界面的. 2.Service能进行后台耗时操作只是因为她的进程级别,并不是因为这个组件本身,因为执行后台操作的根本是工作线程.做应用和系统的都很了解进