【Android源码系列】Service启动源码解析

一、写在前面

上次说了Activity启动,我们接着来看Service。同为四大组件,两者的启动方式相差不多,有了上次的经验,分析起来得心应手。但是我们知道Service有两种方式:start&bind。

Intent intent = new Intent(MainActivity.this, StartService.class);
                startService(intent);
                bindService(intent,serviceConnection,BIND_AUTO_CREATE);

上面的代码想必大家很熟悉了,废话不多说,进入正题。

二、startService方式

直接进入startService方法,我们看到:

    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

是在contextWraper里面,并交给了mBase去执行。往上查找,发现这个mBase是Activity启动时attach方法里生成并传入的。

ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);

发现他是一个ContextImpl对象,继承了context而已。我继续看他的startService方法,发现他调用了自己的startServiceCommon。在startServiceCommon里面我们看到了一行熟悉的代码:

private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess();
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
            //省略部分代码
            return cn;
        } catch (RemoteException e) {
            return null;
        }
    }

这里和Activity启动方式相同,都是通过binder对象进行进程通信,这里我就不多说了,还不清楚的可以先看我的上一篇文章。这里我们直接找到ActivityManegerService(简称AMS)里的startService方法。

public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        if (DEBUG_SERVICE)
            Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }

这个方法也很简单,发现他直接交给mServices处理了,这个mServices是一个ActiveServices的实例,这个类负责Service的很多工作,具体可以下来详细看,这里先不多说。

我们进入到ActiveServices这个类里,发现先调用了startServiceLocked,再调用startServiceInnerLocked,然后继续走到bringUpServiceLocked,最后进入了realStartServiceLocked方法,看名字感觉是真正启动Service的地方了

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

        try {
            if (LOG_SERVICE_START_STOP) {
                String nameTerm;
                int lastPeriod = r.shortName.lastIndexOf('.');
                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                EventLogTags.writeAmCreateService(
                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
            }
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
        } finally {
            if (!created) {
                app.services.remove(r);
                r.app = null;
                scheduleServiceRestartLocked(r, false);
                return;
            }
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
        }

        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
            getServiceMap(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

这个方法很重要,后面我们还需要回头看,这里先分析Service的启动:

 app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);

这句是不是很熟悉,和Activity的启动如出一辙,其实Service启动本来就和Activity相差不大。同样的,我们找到ActivityThread里的scheduleCreateService,同样的,还是通过H这个Handler调用了方法handleCreateService。在这个方法里调用了attach和onCreate,我们的Service正式启动了。

service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();

不过很奇怪的是,我找了很久,往下再也没有出现Onstart之类的生命周期。无奈,只能回头看看,终于在刚刚提到的realStartServiceLocked方法了看到了

       // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
        }

        sendServiceArgsLocked(r, execInFg, true);

看注释大概意思是“这里如果启动过了,将不再调用onStartCommand,如果没有则调用”,所以进去sendServiceArgsLocked方法里瞧瞧,同样的,我们找到了和onCreate启动相同的方式。

 r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);

通过binder跨进程调用了onStartCommand方法,后续原理相同我就不一一贴代码了。这里就把startService启动方式分析完了,发现和Activity启动方式本质上没什么差别,那bind方式呢?

三、bind启动方式

一路查看bind启动的源码,发现TMD和start方式一毛一样,最后都走到了ActiveServices的realStartServiceLocked方法里,执行一遍onCreate。只是不会执行onStartCommand,而是执行了requestServiceBindingsLocked(r, execInFg)方法,同样的,也是跨进程调用了ActivityThread里的方法:

r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);

然后走到handleBindService方法里:

 try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                }

可以看出,onbind方法之会调用一次。
那这样就完了吗?不对呀,bind启动还需要一个东西,ServiceConnection!通过onServiceConnected方法来获取Service传过来的binder对象。好吧,继续看。
我们看到onbind调用之后还会继续调用下面这句话:

ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);

很熟悉的binder通信,我们直接跳到AMS的publishService方法,经过一番辗转,我们看到了这句话:

 void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        //省略无数代码
        try {
            try {
                c.conn.connected(r.name, service);
                            } catch (Exception e) {

                            }
                        }
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

这里调用了conn的connected,好像离成功很近了。我们发现conn是一个IServiceConnection接口,又是一次IPC通信。那我们看看这个c是哪里来的。往上跟踪代码最后找到了ContextImpl里的bindServiceCommon

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            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;
        }
    }

IServiceConnection 对象sd是通过getServiceDispatcher方法得到,继续跟进发现是一个LoadedApk的内部类ServiceDispatcher的内部类InnerConnection (有点绕),继承了IServiceConnection.Stub

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

可以看到,还是调用了sd的connected方法:

public void connected(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0));
            } else {
                doConnected(name, service);
            }
        }

mActivityThread其实就是一个Handler对象,往上翻他其实就H,执行了一个runable,runable里面同样走到了doConnected里,我们来看看这个doConnected

public void doConnected(ComponentName name, IBinder service) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            synchronized (this) {
                if (mForgotten) {
                    // We unbound before receiving the connection; ignore
                    // any connection received.
                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    // Huh, already have this one.  Oh well!
                    return;
                }

                if (service != null) {
                    // A new service is being connected... set it all up.
                    mDied = false;
                    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 not disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }
        }

很轻松的发现里面确实调用了

mConnection.onServiceConnected(name, service);

至此,bind绑定完成。

四、总结

可以发现,无论是start方式还是bind方式,甚至包括Activity启动方式,核心都是通过IPC通信完成的,可见binder在Android里的地位。
那是因为无论是Activity还是Service都涉及到了跨进程启动,比如从你的应用跳转到别的应用,包括跳到Home页面(其实Home界面也是一个进程)。
好的,下一篇将继续分析四大组件,让我们来看看Android这四大组件的原理,这会让我们对Android系统有更加深刻的认识。
最后还是老样子,画出UML图将对整个步骤更加清晰。
这里写图片描述
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值