前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Service 启动与绑定源码分析

Service 启动与绑定源码分析

作者头像
Yif
发布2019-12-25 17:59:15
7290
发布2019-12-25 17:59:15
举报
文章被收录于专栏:Android 进阶Android 进阶
undefined
undefined

Service startService 方法源码分析

在Activity调用startService方法实质调用的是ContextWrapper中的startService方法。

而这个方法调用的是Context的public abstract ComponentName startService(Intent service);方法,由于ContextImpl是Context的具体实现类,Context的大部分操作都是通过ContextImpl来实现的,所以这里的startService方法就是调用的ContextImpl中的startService方法。

代码语言:javascript
复制
 @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
 private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

方法内部调用的是ActivityManager.getService().startService,由于ActivityManager.getService()ActivityManagerService对象,所以调用的就是ActivityManagerService的startService方法

代码语言:javascript
复制
@Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
 
        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }
 
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

方法内部调用了ActiveServicesstartServiceLocked,后续服务启动就是调用startServiceLocked方法,它是帮助管理service的启动、绑定与停止。startServiceLocked内部又调用了startServiceInnerLocked方法。

代码语言:javascript
复制
 ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
}

这里面的ServiceRecord是一个service的记录类,一直存在service的启动过程中,bringUpServiceLocked没有真正启动service,又交给了realStartServiceLocked方法,它是正在启动服务的类,内部调用了ApplicationThread的scheduleCreateService进行创建服务。 方法如下

代码语言:javascript
复制
public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;
 
            sendMessage(H.CREATE_SERVICE, s);
        }

内部通过handler发送一个消息,进行创建服务。

代码语言:javascript
复制
case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

handleCreateService方法

  1. 通过ClassLoader类加载器创建service实例
  2. 创建Application实例
  3. 创建ContextImpl对象,再通过Service的attach进行建立关系
  4. 调用Service的onCreate方法进行创建服务对象,并存储在final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();集合中,ActivityThread类中调用handleServiceArgs方法,该方法中调用onStartCommand启动Service
代码语言:javascript
复制
 private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
 
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    &quot;Unable to instantiate service &quot; + data.info.name
                    + &quot;: &quot; + e.toString(), e);
            }
        }
 
        try {
            if (localLOGV) Slog.v(TAG, &quot;Creating service &quot; + data.info.name);
 
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
 
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    &quot;Unable to create service &quot; + data.info.name
                    + &quot;: &quot; + e.toString(), e);
            }
        }
    }

Service bind 过程

代码语言:javascript
复制
@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

和startService一样,其实调用的是ContextImpl的bindService方法

代码语言:javascript
复制
@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) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException(&quot;connection is null&quot;);
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException(&quot;Not supported in system context&quot;);
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null &amp;&amp; (flags&amp;BIND_AUTO_CREATE) == 0 &amp;&amp; mPackageInfo != null
                    &amp;&amp; mPackageInfo.getApplicationInfo().targetSdkVersion
                    &lt; android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res &lt; 0) {
                throw new SecurityException(
                        &quot;Not allowed to bind to service &quot; + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

该方法中首先将ServiceConnection转换成ServiceDispatcher.InnerConnection对象,由于ServiceConnection不能进行跨进程,而他必须通过binder让远程服务调用自己方法,而InnerConnection实现了IServiceConnection.Stub返回客户端所需的接口对象。

代码语言:javascript
复制
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap&lt;ServiceConnection, LoadedApk.ServiceDispatcher&gt; map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, &quot;Returning existing dispatcher &quot; + sd + &quot; for conn &quot; + c);
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (DEBUG) Slog.d(TAG, &quot;Creating new dispatcher &quot; + sd + &quot; for conn &quot; + c);
                if (map == null) {
                    map = new ArrayMap&lt;&gt;();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

当前arrayMap不为空时,根据当前的ServiceConnection来获取ServiceDispatcher对象,如果为空就创建一个ServiceDispatcher对象,并把它存入mServices集合中,当ServiceDispatcher创建好后,就通过getServiceDispatcher返回InnerConnection对象。 bindService服务实际调用的就是ActivityManagerService中的bindService方法,内部又调用了bindServiceLocked,此时再调用bringUpServiceLocked进入到了ActiveServices类中,内部调用realStartServiceLocked开始真正的绑定服务。

代码语言:javascript
复制
 app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);

最终还是调用ActivityThreadscheduleCreateService,发送一个消息进行服务绑定,最后和startService方法一样完成服务的创建。但是绑定还会调用scheduleBindService,最终调用handleBindService

代码语言:javascript
复制
private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, &quot;handleBindService s=&quot; + s + &quot; rebind=&quot; + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    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);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            &quot;Unable to bind to service &quot; + s
                            + &quot; with &quot; + data.intent + &quot;: &quot; + e.toString(), e);
                }
            }
        }
    }

首先根据mServices取出Service对象,再调用onBind方法,返回这个bind对象就是告诉客户端已经绑定成功了,但是客户端并不知道已经处于连接状态,所有客户端得实现ServiceConnection的onServiceConnection方法,这个过程由AMS的publishService来完成。

代码语言:javascript
复制
 public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null &amp;&amp; intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException(&quot;File descriptors passed in Intent&quot;);
        }
 
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException(&quot;Invalid service token&quot;);
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

内部调用 mServices.publishServiceLocked方法,里面调用了 c.conn.connected(r.name, service, false);c是Connectionrecord,c.conn就是ServiceDispatcherInnerConnection方法,InnerConnection内部connected方法

代码语言:javascript
复制
public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service, dead);
                }
            }
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.post方法切换到主线程中进行操作,所以ServiceConnection是运行在主线程中的,RunConnection也是调用了ServiceDispatcher的doConnected方法,由于内部保存了客户端的ServiceConnection对象,所以方便调用onServiceConnected

代码语言:javascript
复制
// If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }

内部也避免了重复绑定Service,多次绑定同一个Service,onBind对象只会执行一次,除非Service终止。

代码语言:javascript
复制
old = mActiveConnections.get(name);
          if (old != null &amp;&amp; old.binder == service) {
         // Huh, already have this one.  Oh well!
           return;
        }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年9月5日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Service startService 方法源码分析
  • Service bind 过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档