Android Service的绑定流程源码分析(8.0)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pihailailou/article/details/78608537

一,写在前面

       为了更好的理解Service的绑定流程,建议先了解Activity和Service的启动流程,本篇文章将不再对一些重复的细节进行阐述。建议阅读前,可以参考如下两篇文章:

二,绑定服务的开始

       在Activity中调用bindService(intent,ServiceConnection)绑定服务,其实是调用父类ContextWrapper的bindService方法。
       ContextWrapper$bindService方法源码如下:
@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }
       mBase是一个Context类型的对象,mBase的值是一个ContextImpl对象。ContextImpl的实例化是在启动Activity时完成的,并作为参数传入Activity$attach方法,具体细节就点到这里吧,详情可参考 Android Activity的启动流程源码解析(8.0)。也就是说,绑定服务接着交给ContextImpl来处理。

       ContextImpl$bindService方法源码如下:
    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }

    //继续查看...

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
	    IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }

	//...code

	int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
		    
	//...code    
    }
       第5行,调用ContextImpl$bindServiceCommon方法;
       第14行,做一个ServiceConnection接口引用的判空检查;
       第17行,变量mPackageInfo是一个LoadedApk对象,在启动Activity的流程中也会用到这个类,这里做了判空检查;
       第18行,对conn也就是ServiceConnection接口进行封装,借助于一个Binder使ServiceConnection可以在进程间传递,下面会详细分析;
       第25行,ActivityManager.getService()是IActivityManager的代理对象,调用代理对象的bindService方法,会向系统服务ActivityManagerService发起请求,基于Binder机制,调用ActivityManagerService$bindService方法。至于为啥将绑定服务的操作交给AMS,可以参考文章  Android Activity的启动流程源码解析(8.0)  ,这里不再重复阐述。

       分析:
       第18行,调用了LoadedApk$getServiceDispatcher方法。 
       查看LoadedApk源码如下:
public final class LoadedApk {

    //...code

    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<>();
    
    //...code

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

    //...code

    static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;
        private final Context mContext;
        private final Handler mActivityThread;
        private final ServiceConnectionLeaked mLocation;
        private final int mFlags;

        //...code

        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);
                }
            }
        }
    
        //...code

	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;
        }

	//...code

        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }
        
	//...code
    }
}
       第13行,定义了一个ServiceDispatcher类型的变量sd,ServiceDispatcher是LoadedApk的内部类,此时sd为null;
       第5行,创建了一个ArrayMap对象,key是Context对象,value是ServiceConnection和ServiceDispatcher的映射关系,以ArrayMap来体现;
       第14行,取出mServices中key对应的value,第5行只是创建了ArrayMap对象,并没有在集合中添加键值对,map为null;
       第19行,sd == null为true;
       第20~26行,创建ServiceDispatcher对象,并将ServiceConnection对象作为key,ServiceDispatcher对象作为value,存储在变量map集合中;将Context对象作为key,变量map作为value,存储在变量mServices集合中。 
        值得一提的是,在第20行,创建ServiceDispatcher对象时,初始化了变量mIServiceConnection。见第66行,它是一个InnerConnection类型的对象。
       第30行,调用ServiceDispatcher$getIServiceConnection方法,返回mIServiceConnection变量的值,也就是返回一个InnerConnection对象。
       第46行,InnerConnection是ServiceDispatcher的内部类,也就是LoadedApk$ServiceDispatcher$InnerConnection。它继承了IServiceConnection.Stub类,IServiceConnection是一个AIDL接口。这里用到了AIDL技术完成一次IPC调用,AIDL文件生成的Java文件也可以自己写,但是Android系统这里是采用了AIDL技术替代。于是,我们知道IServiceConnection接口的实现类是InnerConnection,后面分析会用到它。

       回到ContextImpl$bindService方法,上面对第18行进行了详细分析,下面继续第25行的流程分析。

三,绑定服务的操作,交给ActivityManagerService处理

       继续ContextImpl$bindService方法的第25行;
       查看ActivityManagerService$bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
    
    //...code

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

    //...code	    	    	    	    
}
       第8行,mServices是一个ActiveServices类型的对象;

       查看ActiveServices$bindServiceLocked方法源码:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
	    
	   //...code
	   
	   if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }

	   //...code

	   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, false);
                } 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, callerFg, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            //...code
	    	    	    
}
       第9行,bringUpServiceLocked方法是不是很熟悉,在文章  Android Service的启动流程源码分析(8.0)中也是调用该方法启动服务的,最终会调用Service$onCreate方法,这里不再重复阐述。
       
       值得一提的是,绑定服务会回到onCreate,onBind,并回调ServiceConnection的方法。事实上,绑定服务有重新绑定这个过程,前提条件是同时调用startService启动了服务,且上一次解绑服务回调的onUnbind方法返回true。重新绑定服务时,会回调onRebind方法,而不再调用onBind方法。可以参考文章  Android Service的onRebind方法调用时机 ,这里不再重复阐述。
      
       第17行,若Service已经处于绑定状态,那么调用bindService只执行21行代码,c.conn.connected里最终回调ServiceConnection的方法。这里不详细描述,后面会给出分析。
       第31行,若重新绑定服务(上面已经分析该过程),则执行32行代码,最后一个参数为true,该过程不具体分析。
       第34行,若没有绑定服务的请求,则执行35行代码,最后一个参数为false, 下面继续分析该过程

       查看ActiveServices$requestServiceBindingLocked源码:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
    }	    

    //...code

    if ((!i.requested || rebind) && i.apps.size() > 0) {
    
        //...code

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

	//...code
    
    }    
    return true;    
}
       第10行,!i.requested为true,则(!i.requested || rebind)为true;i.apps.size()指应用程序进程的数量,i.apps.size() > 0为true。
       继续往下执行到第14行代码,r.app.thread是一个IApplicationThread类型的对象,这个比较熟悉了,它的实现类是ApplicationThread类。文章 Android Activity的启动流程源码解析(8.0) 中,对ApplicationThread类进行了详细分析,这里不再重复阐述。

四,绑定服务的操作,交给ActivityThread处理

       查看ActivityThread$ApplicationThread$scheduleBindService源码:
public final void scheduleBindService(IBinder token, Intent intent,
      boolean rebind, int processState) {
    updateProcessState(processState, false);
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;
    s.rebind = rebind;

    if (DEBUG_SERVICE)
	Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
		+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
}
       查看ActivityThread相关方法的源码:
public final void scheduleBindService(IBinder token, Intent intent,
      boolean rebind, int processState) {
    updateProcessState(processState, false);
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;
    s.rebind = rebind;

    if (DEBUG_SERVICE)
	Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
		+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
}


private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
}

//...继续查看

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
}

//...继续查看

private class H extends Handler {
	
	//...code

	public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
	    
	        //...code

		case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

		//...code
	}
}

//...继续查看

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) {

	    //...code

	    if (!data.rebind) {
               IBinder binder = s.onBind(data.intent);
               ActivityManager.getService().publishService(
                         data.token, data.intent, binder);
            } else {
               s.onRebind(data.intent);
               ActivityManager.getService().serviceDoneExecuting(
                      data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            }
	
	    //...code

	}
}
       第34行,调用mH.sendMessage(msg)发送一个消息。然后,第49行对消息进行处理,调用了handleBindService方法。
       第69行,若没有重新绑定服务,即初次绑定服务,则进入第70行。
       第70行,调用Service$onBind方法,返回Binder对象,并作为参数传递给publishService方法。
       第71行,在绑定服务以后,需要通知客户端已经成功连接Service了,这个操作由AMS的publishService方法来完成, 后面会继续分析这里
       第74行,若重新绑定服务,则回调Service$onRebind方法。

五,通知客户端连接Service成功的操作,交给AMS

       查看ActivityManagerService$publishService方法源码:
public void publishService(IBinder token, Intent intent, IBinder service) {
    //...

    mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    //...
}
       变量mServices是ActiveServices类型;

       查看ActiveServices$publishServiceLocked方法源码:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
	//...code

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

	//...code

}
       c.conn是一个IServiceConnection类型的变量,还记得前面提到的InnerConnection类么,它便是AIDL接口IServiceConnection的实现类。
       查看LoadedApk$ServiceDispatcher$InnerConnection$connected源码:
public void connected(ComponentName name, IBinder service, boolean dead)
	    throws RemoteException {
	LoadedApk.ServiceDispatcher sd = mDispatcher.get();
	if (sd != null) {
	    sd.connected(name, service, dead);
	}
}
       sd是ServiceDispatcher类型的变量;
       查看ServiceDispatcher$connected方法源码:
public void connected(ComponentName name, IBinder service, boolean dead) {
    if (mActivityThread != null) {
	mActivityThread.post(new RunConnection(name, service, 0, dead));
    } else {
	doConnected(name, service, dead);
    }
}
       mActivityThread是一个Handler类型的变量,mActivityThread的初始化在ServiceDispatcher构造方法中完成,它是最开始bindService时一步步传递过来的。mActivityThread就是ActivityThread的内部类H,因此mActivityThread不为空,代码执行到第3行,调用Handler$post方法。
       
       查看LoadedApk$ServiceDispatcher$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方法。ActivityThread是一个主线程,且执行final H mH = new H()创建了H对象,Looper对象是在ActivityThread$main方法中创建,于是run方法在主线程中执行。
       第11行,调用LoadedApk$ServiceDispatcher$doConnected方法;
       查看LoadedApk$ServiceDispatcher$doConnected源码:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
	//...

	// If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }

	//...
}
       第6行,回调ServiceConnection$onServiceConnected方法,通知客户端连接服务成功了。我们经常在该方法获取返回的Binder,调用远程服务接口的方法。值得一提的是,ServiceConnection$onServiceConnected方法的第二个参数service,就是返回给客户端的Binder对象。前面提到run方法在主线程中执行,因此ServiceConnection$onServiceConnected方法是在主线程中被回调。

六,最后
       到这里,绑定服务的流程分析就结束了。值得一提的是,先了解Activity,Service的启动流程对阅读本篇文章大有裨益哦~            ^_^

                                             










       

        


       







猜你喜欢

转载自blog.csdn.net/pihailailou/article/details/78608537