码迷,mamicode.com
首页 > 其他好文 > 详细

bindService流程源码分析

时间:2020-10-09 21:26:50      阅读:32      评论:0      收藏:0      [点我收藏+]

标签:creates   add   roc   enter   依次   receiver   远程   row   pre   

bindService流程源码分析

一、简介

bindService是应用用来与service进行绑定的。该方式启动的service系统认为只有在调用者的context存在时service才有必要运行,比如在activity中调用该方法且该activity处于stopped状态,那么其绑定的服务在activity返回前台前不会运行。
还有就是不能在未注册的BroadcastReceiver调用该方法(只能通过startService来启动service),通过registerReceiver注册的广播可以调用因为此时BroadcastReceiver的生命周期已经和注册对象绑定了。

二、源码分析

bindService是在Context类中定义的具体实现则是在ContextImpl类中。

public abstract boolean bindService(@RequiresPermission Intent service,
        @NonNull ServiceConnection conn, @BindServiceFlags int flags);

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

ContextImpl类中的bindService调用了bindServiceCommon做进一步处理。注意下传入的mMainThread.getHandler()参数,mMainThread是一个ActivityThread实例,所以此处获取的是ActivityThread所在线程的Handler,后面我们就可以通过这个handler把消息分发到ActivityThread线程的消息队列中。

在bindServiceCommon中主要做了两件事一是获取一个IServiceConnection接口,二是调用AMS的远程接口bindService

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
        handler, UserHandle user) {
    // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    IServiceConnection sd;
    //1、调用getServiceDispatcher来获取一个IServiceConnection接口
    if (mPackageInfo != null) {
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    try {
     //2、调用AMS的bindService
        service.prepareToLeaveProcess(this);
        int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
        return res != 0;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

我们来分析下getServiceDispatcher获取IServiceConnection接口的过程。
getServiceDispatcher主要做了以下事情:
根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例,如果没有则创建并存入mServices,最后调用getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象,后续AMS会用它和ServiceConnection通信

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                                                     Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        //1、根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例
        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) {
            //2、mServices中没有对应的ServiceDispatcher实例创建新实例
            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<>();
                //3、存入mServices
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            sd.validate(context, handler);
        }
        //4、getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象后续AMS会用它和ServiceConnection通信
        return sd.getIServiceConnection();
    }
}

我们继续看下ServiceDispatcher的getIServiceConnection,他返回的是ServiceDispatcher.InnerConnection实例,这个是在ServiceDispatcher构造函数内创建的。

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
//….
IServiceConnection getIServiceConnection() {
    return mIServiceConnection;
}

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

}

最后贴下InnerConnection

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

getServiceDispatcher之后就是调用AMS的bindService,如下所示:

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

bindService做了一些检查后调用ActiveServices的bindServiceLocked。
bindServiceLocked比较长我们只看关键部分。它的主要操作可以分为4步具体可以看下面的注释。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                      String resolvedType, final IServiceConnection connection, int flags,
                      String callingPackage, final int userId) throws TransactionTooLargeException {
    //…
    //1、首先会根据token找到其对应的ActivityRecord,我们之前说过ActivityRecord表示的是一个activity记录,此处指的是调用bindService的activity
    ActivityRecord activity = null;
    if (token != null) {
        activity = ActivityRecord.isInStackLocked(token);
        if (activity == null) {
            Slog.w(TAG, “Binding with unknown activity: “ + token);
            return 0;
        }
    }
    //…
    //2、调用retrieveServiceLocked解析传入的intent等参数获得一个ServiceRecord对象
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
    ServiceRecord s = res.record;

    //...
    //3、把传入的connection封装成一个ConnectionRecord对象,connection就是步骤3获得的InnerConnection,
    // 因为后续AMS需要使用它来告诉activity service已经启动起来了,所以要把它保存起来,这里保存在好几个地方
    //AppBindRecord中存储了当前ServiceRecord, intent以及发起方的进程信息。
    AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
    ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);
    IBinder binder = connection.asBinder();
    ArrayList<ConnectionRecord> clist = s.connections.get(binder);
    if (clist == null) {
        clist = new ArrayList<ConnectionRecord>();
        s.connections.put(binder, clist);
    }
    // clist是ServiceRecord.connections的成员变量
    clist.add(c);
     //b是指AppBindRecord
    b.connections.add(c);
    if (activity != null) {
        if (activity.connections == null) {
            activity.connections = new HashSet<ConnectionRecord>();
        }
        activity.connections.add(c);
    }
    b.client.connections.add(c);

    //...
    //4、最初绑定service时传入的flag是BIND_AUTO_CREATE,所以此处符合条件进而调用bringUpServiceLocked启动要绑定的service
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
        s.lastActivity = SystemClock.uptimeMillis();
        if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
            return 0;
        }
    }
    //…
    if (s.app != null) {
            if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                s.app.treatLikeActivity = true;
            }
            //5、更新service所在进程的优先级
            mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                    || s.app.treatLikeActivity, b.client);
            mAm.updateOomAdjLocked(s.app);
        }

        if (s.app != null && b.intent.received) {
            try {
                //6、Service已经正在运行,则调用InnerConnection的代理对象
                c.conn.connected(s.name, b.intent.binder);
            } catch (Exception e) {
                ...
            }
            //7、当第一个app连接到该binding, 且之前已被bind过, 则回调onRebind()方法
            if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                requestServiceBindingLocked(s, b.intent, callerFg, true);
            }
        } else if (!b.intent.requested) {
            //8、最终回调onBind()方法
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
    return 1;
}

bindServiceLocked做的事情比较多,我们再来梳理一下,首先在注释1处查找请求绑定的Activity是否存在,之后在注释2处通过retrieveServiceLocked查找对应的service。在注释3处创建AppBindRecord和ConnectionRecord,AppBindRecord记录着当前ServiceRecord, intent以及发起方的进程信息,ConnectionRecord则是对connection进行封装。创建完成后会把ConnectionRecord存到ServiceRecord和AppBindRecord中。注释4处通过bringUpServiceLocked来启动service,之后在注释5处更新service所在进程的优先级,在注释6处Service已经正在运行,调用InnerConnection的代理对象。注释7处判断是否回调onRebind方法。注释8处requestServiceBindingLocked最终回调onBind()方法。

我们先来看下retrieveServiceLocked查找对应的service的过程,然后再看service绑定过程,至于service启动过程我们之前在startService的源码分析中已经说到过,具体可以参考startService过程源码分析.md

retrieveServiceLocked如下所示:

    private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
             ServiceRecord r = null;
                if (comp != null) {
            //根据service名称查找ServiceRecord
            r = smap.mServicesByName.get(comp);
            if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
        }
        ...
         if (r == null && !isBindExternal) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            //根据Intent查找相应的ServiceRecord
            r = smap.mServicesByIntent.get(filter);
            if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
        }
        ...
         //通过PKMS来查询相应的service
                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                        
           ...
           //创建ServiceRecord对象
           r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
           res.setService(r);
           smap.mServicesByName.put(name, r);
           smap.mServicesByIntent.put(filter, r);
           
           ...
           
            //各种权限检查,不满足条件则返回为null的service
            if (mAm.checkComponentPermission(r.permission,
                    callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
                //当exported=false则不允许启动
                if (!r.exported) {
                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                            + " from pid=" + callingPid
                            + ", uid=" + callingUid
                            + " that is not exported from uid " + r.appInfo.uid);
                    return new ServiceLookupResult(null, "not exported from uid "
                            + r.appInfo.uid);
                }
                
  }

Service查找过程:

  1. 根据服务名从ServiceMap.mServicesByName中查找相应的ServiceRecord,如果没有找到,则往下执行;
  2. 根据Intent从ServiceMap.mServicesByIntent中查找相应的ServiceRecord,如果还是没有找到,则往下执行;
  3. 通过PKMS来查询相应的ServiceInfo,如果仍然没有找到,则不再往下执行。

接下来看下service的绑定:service的启动最终是在realStartServiceLocked里

private final void realStartServiceLocked(ServiceRecord r,
                                          ProcessRecord app, boolean execInFg) throws RemoteException {
    //…
    //1、创建service
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            app.repProcState);
    //...
    //2、调用requestServiceBindingsLocked
    requestServiceBindingsLocked(r, execInFg);

    //...

}

requestServiceBindingsLocked调用requestServiceBindingLocked来进一步处理,通过bindService方式启动的服务, 那么该serviceRecord的bindings则一定不会空。requestServiceBindingLocked里依次调用requestServiceBindingLocked。

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
        throws TransactionTooLargeException {
    for (int I=r.bindings.size()-1; I>=0; I—) {
        IntentBindRecord ibr = r.bindings.valueAt(i);
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

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

    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
           //发送bind开始的消息
            bumpServiceExecutingLocked(r, execInFg, "bind");
            //调用ApplicationThread的scheduleBindService进入bind流程
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
        } catch (TransactionTooLargeException e) {
          //...               
        } catch (RemoteException e) {
            //… 
        }
    }
    return true;
}

我们看到它先发送了bind消息然后调用了ApplicationThread的scheduleBindService进入bind流程。

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;
    //发送BIND_SERVICE message
    sendMessage(H.BIND_SERVICE, s);
}

public void handleMessage(Message msg) {
    case BIND_SERVICE:
    //BIND_SERVICE消息处理
    handleBindService((BindServiceData) msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}

在函数中发送了BIND_SERVICE消息,该消息的的处理是在handleBindService函数中,如下所示

private void handleBindService(BindServiceData data) {
    //1、根据token获取要绑定的service
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    //2、回调service的onBind
                    IBinder binder = s.onBind(data.intent);
                    //3、把步骤2得到的binder(即onBind的返回值)传递给AMS
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    s.onRebind(data.intent);
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
           //…
        }
    }
}

在该函数中首先根据token获取要绑定的service,之后回调service的onBind拿到一个binder对象(这个binder就是onBind的返回值),最后传递给AMS。

AMS的publishService如下所示:

public void publishService(IBinder token, Intent intent, IBinder service) {
    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 {
        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;
                for (int conni=r.connections.size()-1; conni>=0; conni—) {
                    //1、从ServiceRecord.connections中取出ConnectionRecord
                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                    for (int I=0; I<clist.size(); I++) {
                        ConnectionRecord c = clist.get(i);
                        try {
                            //2、调用ConnectionRecord.conn.connected,此处的ConnectionRecord.conn是之前创建的LoadedApk.ServiceDispatcher.InnerConnection对象
                            c.conn.connected(r.name, service, false);
                        } catch (Exception e) {
                            //...
                        }
                    }
                }
            }
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

InnerConnection的connected函数如下所示:

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) {
            //调用ServiceDispatcher的connected
            sd.connected(name, service, dead);
        }
    }
}

它调用了ServiceDispatcher的connected,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,通过该Handler post消息。

RunConnection的run如下

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进行绑定
            doConnected(mName, mService, mDead);
        } else if (mCommand == 1) {
            doDeath(mName, mService);
        }
    }

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

doConnected函数如下:

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

 if (service != null) {
                    // A new service is being connected... set it all up.
                    info = new ConnectionInfo();
                    info.binder = service;
                    //创建死亡监听对象
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                       //建立死亡通知
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        // This service was dead before we got it...  just
                        // don‘t do anything with it.
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    // The named service is being disconnected... clean up.
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            // If there was an old service, it is now disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
                mConnection.onBindingDied(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
            //回调onServiceConnected,至此我们就在绑定端的onServiceConnected回调函数中拿到service返回的binder了
                mConnection.onServiceConnected(name, service);
            }
}

在doConnected函数中首先会创建死亡监听对象并建立死亡通知,之后会回调onServiceConnected。

至此bindService的过程就结束了,总结来整个过程大概分为以下几步:
1、首先调用bindService通知AMS绑定service,AMS会先启动service回调其onCreate函数。
2、AMS启动service完成之后继续调用service的onBind函数,获取service返回的binder。
3、AMS把上一步获得的Binder对象通过绑定时传入的ServiceConnection的onServiceConnected函数传给调用端,这样调用端就可以通过binder来调用service提供的相关方法。

  1. Client进程: 通过getServiceDispatcher获取Client进程的匿名Binder服务端,即LoadedApk.ServiceDispatcher.InnerConnection,该对象继承于IServiceConnection.Stub; 再通过bindService调用到system_server进程;
  2. system_server进程: 依次通过scheduleCreateService和scheduleBindService方法, 远程调用到target进程;
  3. target进程: 依次执行onCreate()和onBind()方法; 将onBind()方法的返回值IBinder(作为target进程的binder服务端)通过publishService传递到system_server进程;
  4. system_server进程: 利用IServiceConnection代理对象向Client进程发起connected()调用, 并把target进程的onBind返回Binder对象的代理端传递到Client进程;
  5. Client进程: 回调到onServiceConnection()方法, 该方法的第二个参数便是target进程的binder代理端. 到此便成功地拿到了target进程的代理, 可以畅通无阻地进行交互.

参考:

bindService启动过程分析

bindService流程源码分析

标签:creates   add   roc   enter   依次   receiver   远程   row   pre   

原文地址:https://www.cnblogs.com/Robin132929/p/13786514.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!