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

来源:互联网 发布:用java编写冒泡排序 编辑:程序博客网 时间:2024/05/16 05:58

一、写在前面

上次说了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 0
原创粉丝点击