Activity组件之一Service--- BindService & unBindService


接着上一篇StartService,这章分析一下bindService的一个流程。

在Android developer网站上有三种使用创建Bound Service的方法:

    一种就是继承Binder Class的,这种方法用在当你的Service只会用在自己的进程当中,而不会出现换进程的调用。也就是所谓的LocalService.

   一种是使用Messager,这是通过使用Handler相关的东西,去实现跨进程的调用。

    最后一种就是AIDL,最常用的一种跨进程的Service binder调用。

1. ContextImpl.bindService()

    通常我们想去调用一个Service的时候,会传递一个Intent和一个ServiceConnection还有一个flags参数。ServiceConnection是需要我们继承的。

    flags:Operation options for the binding

    1. 通过mPackageInfo.getServiceDispatcher(conn, getOuterContext(),mMainThread.getHandler(), flags);   

    2. 通过ActivityManagerNative去远程调用AMS。

    public boolean bindService(Intent service, ServiceConnection conn,int flags) {
        warnIfCallingFromSystemProcess();
        return bindService(service, conn, flags, UserHandle.getUserId(Process.myUid()));
    }

    /** @hide */
    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) {
        IServiceConnection sd;

        try {
            IBinder token = getActivityToken();
            if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);                                                                                                                 ... ...
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(),
                service, service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, userHandle);
            ... ...
            return res != 0;
        } catch (RemoteException e) {
            return false;
        }
    }


1.1 LoaderApk.getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags)

       在ServiceDispatcher会保存着传进来的ServiceConnection,同时有一个InnerConnection对象,而InnerConnection是继承自IServiceConnection.Stub,所以InnerConnection是一个Binder的服务端。sd.getIServiceConnection()返回的就是InnerConnection对象mIServiceConnection。 

       里面有两个Map数组,一个context对应一组(ServiceConnection和ServiceDispatcher的map),一个ServiceConnection对应一个ServiceDispatcher。

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            HashMap 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 HashMap();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }


        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference(sd);
            }

            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }

        private final HashMap mActiveConnections
            = new HashMap();

        ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
        }


2. AMS.bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType,  IServiceConnection connection, int flags, int userId)

  1. 直接调用mServices.bindServiceLocked

    public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType,
            IServiceConnection connection, int flags, int userId) {
        enforceNotIsolatedCaller("bindService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service, resolvedType,
                    connection, flags, userId);
        }
    }

2.1 ActiveService.bindServiceLocked(IApplicationThread caller, IBinder token,  Intent service, String resolvedType,  IServiceConnection connection, int flags, int userId)

    1. 通过传进来的token值到ActivityStack中查询该token值是不是已经有了,就是调用者Activity的 ActivityRecord

    2. 通过retrieveServiceLocked找到需要bind的service放到新的ServiceRecord中

    3.  新建AppBindRecord, ConnectionRecord, 获取Clinet端传过来的ServiceDispatcher.InnerConnection的IBinder,把IBinder与ConnectionRecord建立关系并保持在对应的connections中。

    4. bringUpServiceLocked, 启动Service // goto 2.1.4 

    int bindServiceLocked(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType,
            IServiceConnection connection, int flags, int userId) {

        ActivityRecord activity = null;
        if (token != null) {
            activity = mAm.mMainStack.isInStackLocked(token);
            if (activity == null) {
                Slog.w(TAG, "Binding with unknown activity: " + token);
                return 0;
            }
        }                                                                                                                                                         ... ...
        int clientLabel = 0;
        PendingIntent clientIntent = null;
        ... ...
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true);

        ServiceRecord s = res.record;

        try {
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
            ArrayList clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);
            if (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
                    return 0;
                }
            }

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

            if (s.app != null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                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.
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
    }

2.1.4 ActiveServices.bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting)

      1. 如果这个Service所在的进程已经起来了,就直接调用realStartServiceLocked(r, app);   如果这个Service还没有起来就先去mAm.startProcessLocked启动对应的process,然后把需要start的service添加到mPendingServices中,等到进程起来之后会调用attachApplicationLocked去启动相应的service,当然还是调用realStartServiceLocked(sr, proc);

private final String bringUpServiceLocked(ServiceRecord r,
            int intentFlags, boolean whileRestarting) {


        // Service is now being launched, its package can't be stopped.
        try {
            AppGlobals.getPackageManager().setPackageStoppedState(
                    r.packageName, false, r.userId);
        } catch (RemoteException e) {
        } catch (IllegalArgumentException e) {
            Slog.w(TAG, "Failed trying to unstop package "
                    + r.packageName + ": " + e);
        }

        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
            if (DEBUG_MU)
                Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName);
                    realStartServiceLocked(r, app);
                    return null;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
            // If this service runs in an isolated process, then each time
            // we call startProcessLocked() we will get a new isolated
            // process, starting another process if we are currently waiting
            // for a previous process to come up.  To deal with this, we store
            // in the service any current isolated process it is running in or
            // waiting to have come up.
            app = r.isolatedProc;
        }


        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        return null;
    }

2.1.4.1 ActiveService.realStartServiceLocked(ServiceRecord r, ProcessRecord app) 

         app.services.add(r);   //把record加到service所在的进程的ProcessRecord的services的数组中
         bumpServiceExecutingLocked(r, "create");   // 把service加到 r.app.executingServices中,说明这个servcie正在执行。

     1) app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo)); 通过app.thread.scheduleCreateService去调用ActivityThread的scheduleCreateService。在ActivityThread的中通过handle去发送和处理“CREATE_SERVICE”的消息。调用handleCreateService

     2)  requestServiceBindingLock()  //这个函数在BindService的时候才会起作用 

     3)  sendServiceArgsLocked(r, true); //没有传递的参数,在这边没用

       private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app) throws RemoteException {
        ... ...
        app.services.add(r);
        bumpServiceExecutingLocked(r, "create");
        mAm.updateLruProcessLocked(app, true);


        boolean created = false;
        try {
            ... ...
            EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
                    r.userId, System.identityHashCode(r), r.shortName,
                    mAm.mStringBuilder.toString(), r.app.pid);
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
            r.postNotification();
            created = true;
        } finally {
            if (!created) {
                app.services.remove(r);
                scheduleServiceRestartLocked(r, false);
            }
        }

        requestServiceBindingsLocked(r);


        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
        }


        sendServiceArgsLocked(r, true);
    }

2.1.4.1.2 ActiveService.requestServiceBindingsLocked(ServiceRecord r) 

     1) 调用 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); 去调用ActivityThread的方法

    private final void requestServiceBindingsLocked(ServiceRecord r) {
        Iterator bindings = r.bindings.values().iterator();
        while (bindings.hasNext()) {
            IntentBindRecord i = bindings.next();
            if (!requestServiceBindingLocked(r, i, false)) {
                break;
            }
        }
    }

    private final boolean requestServiceBindingLocked(ServiceRecord r,
            IntentBindRecord i, boolean rebind) {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, "bind");
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
                return false;
            }
        }
        return true;
    }

2.1.4.1.2.1 ActivityThread.handleBindService()

    1) 找到对应的Service,并且调用Service.onBind(自己写的Service都是要实现onBind来返回一个IBinder用来与之交互的), 把返回的IBinder值传回ActiveService, 调用                  ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder);

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, 0, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
            ... ...
        }
    }

2.1.4.1.2.1.1 ActiveServcie.publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) 

   里面的细节先不关注,这里主要看c.conn.connected(r.name, service); 这个就调到我们之前传进来的ServiceDispatcher.InnerConnection的connected(), 最终就用调用mConnection.onServiceConnected(name, service); 也就是ServiceConnection.onServiceConnected。

    ServiceConnection.onServiceConnected传进来的Binder就是Service.onBind()返回的值。

    所以这就建立了ServiceConnection与Service之间的关系。

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
                    + " " + intent + ": " + service);
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    if (r.connections.size() > 0) {
                        Iterator> it
                                = r.connections.values().iterator();
                        while (it.hasNext()) {
                            ArrayList clist = it.next();
                            for (int i=0; i

3. ContextImpl.unbindSercie

    1) 通过ActivityManagerNative.getDefault().unbindService(sd); 调用ActiveServices.unbindServiceLocked

    public void unbindService(ServiceConnection conn) {
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                    getOuterContext(), conn);
            try {
                ActivityManagerNative.getDefault().unbindService(sd);
            } catch (RemoteException e) {
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
    }

3.1 ActiveServices.unbindServiceLocked(IServiceConnection connection) 

   1) 根据传进来的ServiceDispatcher.InnerConnection的IBinder值获取对应的ConnectionRecord的list,然后依次调用removeConnectionLocked(r, null, null);

    boolean unbindServiceLocked(IServiceConnection connection) {
        IBinder binder = connection.asBinder();
        if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
        ArrayList clist = mServiceConnections.get(binder);
        if (clist == null) {
            Slog.w(TAG, "Unbind failed: could not find connection for "
                  + connection.asBinder());
            return false;
        }

        final long origId = Binder.clearCallingIdentity();
        try {
            while (clist.size() > 0) {
                ConnectionRecord r = clist.get(0);
                removeConnectionLocked(r, null, null);

                if (r.binding.service.app != null) {
                    // This could have made the service less important.
                    mAm.updateOomAdjLocked(r.binding.service.app);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return true;
    }

3.1.1 ActiveServices.removeConnectionLocked( ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) 

    1) s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent()); 回调ActivityThread的handleUnbindService,在这个函数中会去s.onUnbind 去做service unBind的动作。

    2) bringDownServiceLocked(s, false);  

    void removeConnectionLocked(
        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
        IBinder binder = c.conn.asBinder();
        AppBindRecord b = c.binding;
        ServiceRecord s = b.service;
        ArrayList clist = s.connections.get(binder);
        if (clist != null) {
            clist.remove(c);
            if (clist.size() == 0) {
                s.connections.remove(binder);
            }
        }
        b.connections.remove(c);
        if (c.activity != null && c.activity != skipAct) {
            if (c.activity.connections != null) {
                c.activity.connections.remove(c);
            }
        }
        if (b.client != skipApp) {
            b.client.connections.remove(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.updateHasAboveClientLocked();
            }
        }
        clist = mServiceConnections.get(binder);
        if (clist != null) {
            clist.remove(c);
            if (clist.size() == 0) {
                mServiceConnections.remove(binder);
            }
        }

        if (b.connections.size() == 0) {
            b.intent.apps.remove(b.client);
        }

        if (!c.serviceDead) {
            if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
                    + ": shouldUnbind=" + b.intent.hasBound);
            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                    && b.intent.hasBound) {
                try {
                    bumpServiceExecutingLocked(s, "unbind");
                    mAm.updateOomAdjLocked(s.app);
                    b.intent.hasBound = false;
                    // Assume the client doesn't want to know about a rebind;
                    // we will deal with that later if it asks for one.
                    b.intent.doRebind = false;
                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                } catch (Exception e) {
                    Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                    serviceDoneExecutingLocked(s, true);
                }
            }

            if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                bringDownServiceLocked(s, false);
            }
        }
    }

3.1.1.2 ActiveServices.bringDownServiceLocked(ServiceRecord r, boolean force)

    1) 如果force == false也就是并没有要求强制退出,r.connections.size() > 0 说明 这个Service还有其他Client Bind存在就直接return;  要不然r.connections.size() == 0, 说明多有的Client端都已经调用了unbind了,此时就会去把这个Service给destroy掉,通过调用r.app.thread.scheduleStopService(r);

        此时s.onDestroy();就会被调用,也就是一个Service的生命周期结束。

    2) mStoppingServices.add(r);   //加到mStoppingServices数组中。

    private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
        //Slog.i(TAG, "Bring down service:");
        //r.dump("  ");

        // Does it still need to run?
        if (!force && r.startRequested) {
            return;
        }
        if (r.connections.size() > 0) {
            if (!force) {
                // XXX should probably keep a count of the number of auto-create
                // connections directly in the service.
                Iterator> it = r.connections.values().iterator();
                while (it.hasNext()) {
                    ArrayList cr = it.next();
                    for (int i=0; i> it = r.connections.values().iterator();
            while (it.hasNext()) {
                ArrayList c = it.next();
                for (int i=0; i


3.1.1.2.1 ActivityThread.handleStopService

       当handleStopService执行完后,还是会调用ActiveServices.serviceDoneExecutingLocked告诉AMS客户端已经执行完成了。

       此时inStopping为true,因为这个ServiceRecord已经加到mStoppingServices中

    void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
        boolean inStopping = mStoppingServices.contains(r);
        if (r != null) {
            ... ...
            final long origId = Binder.clearCallingIdentity();
            serviceDoneExecutingLocked(r, inStopping);
            Binder.restoreCallingIdentity(origId);
        } else {
            Slog.w(TAG, "Done executing unknown service from pid "
                    + Binder.getCallingPid());
        }
    }

    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
        if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
                + ": nesting=" + r.executeNesting
                + ", inStopping=" + inStopping + ", app=" + r.app);
        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
        r.executeNesting--;
        if (r.executeNesting <= 0 && r.app != null) {
            if (DEBUG_SERVICE) Slog.v(TAG,
                    "Nesting at 0 of " + r.shortName);
            r.app.executingServices.remove(r);
            if (r.app.executingServices.size() == 0) {
                if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
                        "No more executingServices of " + r.shortName);
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
            }
            if (inStopping) {
                if (DEBUG_SERVICE) Slog.v(TAG,
                        "doneExecuting remove stopping " + r);
                mStoppingServices.remove(r);
                r.bindings.clear();
            }
            mAm.updateOomAdjLocked(r.app);
        }
    }



你可能感兴趣的:(Android)