bindService源码流程

前沿

上一篇文章给大家分析了一下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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容