Android Service的绑定过程

本文内容多是出自《Android进阶解密》一书。所以,可能不会为大家提供多少帮助,我写本文的目的只是为了自己再学习的时候能够有个印象,为自己提供一个方便。

Service的绑定过程分为两个部分,分别是ContextImpl到AMS的调用过程和Service的绑定过程。

在开始学习之前,先将几个相关的类介绍一下。

ServiceRecord:跟ActivityRecord功能类似,ActivityRecord用来描述一个Activity,相应的ServiceRecord就是用来描述一个Service。

ProcessRecord:描述一个进程的信息。

ConnectionRecord:描述应用程序进程和Service建立的一次通信。

IntentBindRecord:用于描述绑定Service的Intent。

AppBindRecord:应用程序进程通过Intent绑定Service时,会通过AppBindRecord来维护Service与应用程序进程之间的关联。

一、ContextImpl到AMS的调用过程

这一过程跟在学习Service的启动过程中的ContextImpl到AMS的调用过程是极其相似的。首先我们在其他组件中通过bindService来绑定Service时会调用到ContextWrapper类的bindService方法。其代码实现如下:

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}

Android Service的启动过程一文中我们分析过mBase指的就是ContextImpl,接着查看ContextImpl的bindService方法。代码如下:

@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }

在bindService方法中,返回了bindServiceCommon方法。现在看一下此方法中做了些什么重要的操作。其代码如下:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {

        IServiceConnection sd;
        // 注释1
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            // 注释2
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            // 注释3
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

注释1处,对ServiceConnection对象做了非空的判断,当其为空时抛出了一个“connection is null”的异常。所以,在调用bindService方法时,传入的ServiceConnection对象一定为非空的。注释2处,调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd。注释3处的代码我们并不陌生,最终会调用到AMS的bindService方法。至此ContextImpl到AMS的调用过程就结束了。这一过程的时序图如下:

二、Service的绑定过程

此时代码已经执行到AMS的bindService方法,该方法中返回了ActiveServices类的bindServiceLocked方法。现在看一下bindServiceLocked方法中做了什么处理。关键代码如下:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
        // 代码省略。。。。

        try {
            
            // 代码省略。。。
            // 注释1
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            //。。。。

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

            // 。。。。
            // 注释3
            if (s.app != null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                try {
                    // 注释4
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortName
                            + " to connection " + c.conn.asBinder()
                            + " (in " + c.binding.client.processName + ")", e);
                }

                // 注释5
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    // 注释6
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {// 注释7
                // 注释8
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
    }

bindServiceLocked方法中,关键性的代码比较多。其中,注释1处:调用了ServiceRecord的retriveAppBindingLocked方法来获得AppBindRecord。注释2处的判断条件表明此时Service还没有启动,调用bringUpServiceLocked方法启动Service。Service启动的过程在上篇文章已经学习过了此处不再赘述。注释3处s.app!=null表示Service已经启动。s表示ServiceRecord,app表示ProcessRecord类型的对象。b.intent.received表示当前应用程序进程已经接收到绑定Service时返回的Binder。注释4,调用c.conn的connected方法,c.conn指代IServiceConnection,具体实现是ServiceDispatcher.InnerConnection。注释5表示如果当前应用程序进程是第一个与Service进行绑定的,并且Service已经调用了onUnBind方法。看一下b.intent.doRebind为true为什么表明Service调用了onUnBind方法。跟进b.intent代码,进入到IntentBindRecord类找到变量doRebind。注释为:

/** Set when the service's onUnbind() has asked to be told about new clients. */
boolean doRebind;

注释的意思是:当Service的onUnBind方法被调用并且通知到新的客户端的时候被设置。

注释6和注释8调用的方法是一致的,只不过最后一个参数boolean类型的rebind的值不一样。注释6传入true表示是重新绑定,需要回调onRebind;而注释8传入的false表明不是重新绑定,不需要回调onRebind。注释7,"!b.intent.requested"表明Client端没有发送过绑定Service的请求。接下来看一下requestServiceBindingLocked方法做了什么处理。代码如下:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        
        // 。。。
        // 注释1
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                
                // 注释2

                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
                
                //。。。
            }
        }
        return true;
    }

有两处需要注意的。注释1:"!i.requested"表示没有发送过绑定Service的请求,而rebind表示是否需要重新绑定Service。上面分析bindServiceLocked方法中注释5和注释7的时候提到过,注释5b.intent.app.size() == 1表明是第一个与Service绑定的,所以通过注释6调用到的requestServiceBindingLocked方法注释1中"!i.requested"不成立,但是rebind为true是成立的;如果在注释7的判断条件下通过注释8调用到的requestServiceBindingLocked方法注释1中"!i.requested"是成立的,但是rebind为true是不成立的。所以,此处(!i.requested || rebind)总会得到满足,而后面的i.apps.size() > 0 表示所有用当前Intent绑定Service的应用程序进程个数大于0。跟进i.apps的代码。如下:

final class IntentBindRecord {

    // 。。。。    

    /** All apps that have bound to this Intent. */
    final ArrayMap<ProcessRecord, AppBindRecord> apps
            = new ArrayMap<ProcessRecord, AppBindRecord>();
}

此时,我们回到bindServiceLocked方法的注释1处,ServiceRecord的retrieveAppBindingLocked方法。代码如下:

public AppBindRecord retrieveAppBindingLocked(Intent intent,
            ProcessRecord app) {
        Intent.FilterComparison filter = new Intent.FilterComparison(intent);
        IntentBindRecord i = bindings.get(filter);
        if (i == null) {
            // 注释1
            i = new IntentBindRecord(this, filter);
            bindings.put(filter, i);
        }
        // 注释2
        AppBindRecord a = i.apps.get(app);
        if (a != null) {
            return a;
        }
        // 注释3
        a = new AppBindRecord(this, i, app);
        i.apps.put(app, a);
        return a;
    }

注释1处创建了IntentBindRecord,注释2处,根据ProcessRecord获得IntentBindRecord中存储的AppBindRecord,如果AppBindRecord不为null就直接返回,如果为null就在注释3处创建AppBindRecord,并将ProcessRecord作为key,AppBindRecord作为value保存在IntentBindRecord的apps(i.apps)中。因此,requestServiceBindingLocked方法注释1中i.apps.size()>0成立。所以该方法中注释2处的代码:r.app.thread.scheduleBindService方法就会得到调用。之前分析过r.app.thread指代的是IApplicationThread,而ApplicationThread是ActivityThread的内部类,这样代码就执行到了ApplicationThread的scheduleBindService方法。该方法的最后通过sendMessage方法向H类发送了一条BIND_SERVICE类型的消息。之前就已经提到过,H是ActivityThread类的内部类继承了Handler。我们接着看H的handleMessage方法中对BIND_SERVICE类型消息的处理。代码如下:

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                // 代码省略。。。。
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    // 关键代码
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

                // 代码省略。。。。

            }
            //。。。。
        }

handleMessage方法中关键代码就是调用了handleBindService方法。现在看一下其中做了什么操作,代码如下:

private void handleBindService(BindServiceData data) {
        // 注释1
        Service s = mServices.get(data.token);
        
        // 代码省略。。。
                try {
                    // 注释2
                    if (!data.rebind) {
                        // 注释3
                        IBinder binder = s.onBind(data.intent);
                        // 注释4
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        // 注释5
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
           
        }
    }

注释1处,从Map集合中获取要绑定的Service。注释2处,如果传递进来的BindServiceData.rebind为false(对应bindServiceLocked方法中注释8处的调用),就会调用注释3中的代码来调用Service的onBind方法,并且将IBinder对象返回到onBind方法,至此Service就处于绑定状态了。相反,如果传递进来的BindServiceData.rebind为true时(对应bindServiceLocked方法中注释6处的调用)就会调用Service的onRebind方法。此处结合bindServiceLocked方法的注释5处得出的结论就是:如果当前应用程序进程第一个与Service进行绑定,并且Service已经调用过onUnBind方法,则会调用Sservice的onRebind方法。在ActivityThread的handleBindService方法的注释5这种情况是之前已经进行过绑定,不做分析。只分析之前没有绑定过Service的情况,此时看注释4处的代码,调用了AMS的publishService方法。

public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            // 关键代码。。。
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

调用了ActiveServices的publishServiceLocked方法。代码如下:

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        
        try {
              // 关键代码。。。
              c.conn.connected(r.name, service, false);
        } catch (Exception e) {
            Slog.w(TAG, "Failure sending service " + r.name +
            " to connection " + c.conn.asBinder() +
            " (in " + c.binding.client.processName + ")", e);
        }
    }

在ActiveServices.publishServiceLocked方法中,关键代码就是调用了

c.conn.connected(r.name, service, false);

c.conn指的是IServiceConnection它是ServiceConnection在本地的代理,用于解决当前应用程序进程和Service跨进程通信的问题,具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,ServiceDispatcher.InnerConnection的connected方法代码如下:

static final class ServiceDispatcher {

    .....

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

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

            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    // 关键代码。。。
                    sd.connected(name, service, dead);
                }
            }
    }

    .....

}

关键代码调用了ServiceDispatcher的connected方法。代码:

public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
                // 注释1:指代的是向Handler发送消息
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                // 注释2
                doConnected(name, service, dead);
            }
        }

注释1处,调用Handler类型的对象mActivityThread的post方法,将RunConnection对象的内容运行在主线程中。RunConnection的定义如下:

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

            public void run() {
                if (mCommand == 0) {
                    // 关键代码
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }

RunConnection实现了Runnable接口,其run方法中调用了doConnected方法。这和connected方法注释2中调用的方法是一致的。这就说明代码执行到此处无论什么情况都会调用doConnected方法。其代码如下:

public void doConnected(ComponentName name, IBinder service, boolean dead) {

     ServiceDispatcher.ConnectionInfo old;
     ServiceDispatcher.ConnectionInfo info;
            
    ......
    // If there was an old service, it is now disconnected.
    if (old != null) {
        // 注释1.。。
        mConnection.onServiceDisconnected(name);
    }
    if (dead) {
        mConnection.onBindingDied(name);
    }
    // If there is a new service, it is now connected.
    if (service != null) {
        // 注释2.。。
        mConnection.onServiceConnected(name, service);
    }
}

根据代码中的注释我们也能明白,如果此时有之前的service,就会调用ServiceConnection的onServiceDisConnected方法。如果此时传递进来的IBinder类型的service不为空就会调用ServiceConnection的onServiceConnected回调方法。至此,Service的绑定过程就学习完了。最后附上绑定过程的时序图。如下:

至此,Service的整个绑定过程就学习完成了。本文到此也就结束了。感谢《Android进阶解密》一书的作者,刘望舒先生。

猜你喜欢

转载自blog.csdn.net/zhourui_1021/article/details/105644942
今日推荐