bindService源码流程

2018-05-26  本文已影响0人  loveCandyTQJ

前沿

上一篇文章给大家分析了一下Binder的交互流程,这篇文章分析一下上篇遗留的bindService执行流程,当我们调用了bindService系统为我们做了些什么。

首先,当我们想要去绑定一个远程service时,我们需要写以下代码:

    Intent intent = new Intent(this,MyService.class);
    bindService(intent,connection,BIND_AUTO_CREATE);

这时候我们就要进入bindService

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

这时候我们发现这个调用了mBase.bindService.进入这个方法才发现是个抽象方法。我去,那怎么办,我们需要找到他真正的子类实现,这里就不给大家卖关子了,我们真正的子类实现是ContextImpl这个类,那我们去看一下这个类中的bindService吧。

    @Override                                                                         
    public boolean bindService(Intent service, ServiceConnection conn,                
            int flags) {                                                              
        warnIfCallingFromSystemProcess();                                             
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());       
    }                                                                                 
 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,   
         UserHandle user) {                                                             
     IServiceConnection sd;                                                                                                                                          
     if (mPackageInfo != null) { 
         //这里先记录以下,一会还会回来                                                    
         sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),                
                 mMainThread.getHandler(), flags);                                      
     }                                                                               
     validateServiceIntent(service);                                                    
     try {                                                                              
         IBinder token = getActivityToken();                                            
         //省略一些代码。                                                           
         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;                                                               
     } catch (RemoteException e) {                                                      
         return false;                                                                  
     }                                                                                  
 }                                                                                      

这时候就会调用ActivityManagerNative.getDefault().bindService这个ActivityManagerNative.getDefault()代码如下:

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

通过ServiceManager 去获取了一个binder,并把这个binder返回了,是一个IActivityManager如果大家看过很多底层代码就会很熟悉这样的接口类,我们通过这个接口可以猜出其子类是ActivityManagerService。我们去这个类中的bindService一探究竟。

public int bindService(IApplicationThread caller, IBinder token,
        Intent service, String resolvedType,
        IServiceConnection connection, int flags, int userId) {
    synchronized(this) {
        return mServices.bindServiceLocked(caller, token, service, resolvedType,
                connection, flags, userId);
    }
}

调用了bindServiceLocked方法

// 省略掉一些有关Activity的启动流程,我们再后面再说
   private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        requestServiceBindingsLocked(r, execInFg);
   }

最后会调用requestServiceBindingsLocked方法

private final boolean requestServiceBindingLocked(ServiceRecord r,
        IntentBindRecord i, boolean execInFg, 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, execInFg, "bind");
            r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
            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;
}

这里我们看r.app.thread.scheduleBindService这个方法,但是你又会问,点不进去啊,这个scheduleBindService在哪里呢。我们进到ProcessRecord里面看一下

final class ProcessRecord {
    private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
    final ApplicationInfo info; // all about the first app in the process
    final boolean isolated;     // true if this is a special isolated process
    final int uid;              // uid of process; may be different from 'info' if isolated
    final int userId;           // user of process.
    final String processName;   // name of the process
    // List of packages running in the process
    final ArrayMap<String, ProcessStats.ProcessState> pkgList
            = new ArrayMap<String, ProcessStats.ProcessState>();
    IApplicationThread thread;

发现又是一个IApplicationThread那我们的实现类是是就可以猜出是ApplicationThread这个类呢,其实这样想我们是对的,但是在这里你是找不到这个类的,我在开始找的时候也很头疼,找了半天发现不是我所想的那样。这里的ApplicationThread是一个内部类,它在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;
    Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
}

这里通过H 发送了一个BIND_SERVICE消息

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

调用了handleBindService方法

private void handleBindService(BindServiceData data) {
    //从记录中获取一个service对象,每次启动Service,系统都会记录到mServices中
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            try {
                //判断service是否未绑定过了
                if (!data.rebind) {
                    //没有绑定需要走onBind
                    IBinder binder = s.onBind(data.intent);
                    ActivityManagerNative.getDefault().publishService(
                            data.token, data.intent, binder);
                } else {
                    //绑定过需要走onRebind
                    s.onRebind(data.intent);
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, 0, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to bind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

这里会判断是否已经绑定过了,如果未绑定就回调onBind方法,绑定过了就会回调onRebingd方法。最后会调用publishService方法,我们在前面见过这个类,而且知道他的子类是ActivityManagerService,那我们去里面看看吧。

public void publishService(IBinder token, Intent intent, IBinder service) {
    synchronized(this) {
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
}

调用了publishServiceLocked这里我们只贴关键代码

for (int conni=r.connections.size()-1; conni>=0; conni--) {
    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
    for (int i=0; i<clist.size(); i++) {
        ConnectionRecord c = clist.get(i);
        if (!filter.equals(c.binding.intent.intent)) {
            if (DEBUG_SERVICE) Slog.v(
                    TAG, "Not publishing to: " + c);
            if (DEBUG_SERVICE) Slog.v(
                    TAG, "Bound intent: " + c.binding.intent.intent);
            if (DEBUG_SERVICE) Slog.v(
                    TAG, "Published intent: " + intent);
            continue;
        }
        if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
        try {
            c.conn.connected(r.name, service);
        } catch (Exception e) {
            Slog.w(TAG, "Failure sending service " + r.name +
                  " to connection " + c.conn.asBinder() +
                  " (in " + c.binding.client.processName + ")", e);
        }
    }
}

这时候就会去ConnectionRecord list中去查找,找到就开始调用c.conn.connected(r.name, service),那这个conn又是什么呢,我们点进去看一下。

final class ConnectionRecord {
    final IServiceConnection conn; 

是不是感觉很熟悉,那我们按照以前的套路去查一下ServiceConnection这个类吧,但是你会失望的发现他还是个接口,那咋办,还记得我在上面有个地方说一会还会回来看这里的地方么。我们去看看。

 if (mPackageInfo != null) {                                            
     sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),    
             mMainThread.getHandler(), flags);                          
 }                                                             

发现进入到了LoadedApk中的getServiceDispatcher

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) {
            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();
    }
}

这里把LoadedApk.ServiceDispatcher放进了一个map中,这里就是我们上面要找的那个conn,让我们看一下这个类的实现吧。

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) throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            sd.connected(name, service);
        }
    }
}

public void connected(ComponentName name, IBinder service) {
        doConnected(name, service);
}

public void doConnected(ComponentName name, IBinder service) {
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    }
}

经过一连串的方法调用,终于看到了我们认识的方法mConnection.onServiceConnected(name, service);
最后会吧IBinder回调到我们的客户端。到这里bindService的流程就完了。

UML图如下:
bindService.jpg

喜欢的请大家点赞哦!不对的地方请留言指出,谢谢。

上一篇下一篇

猜你喜欢

热点阅读