专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
stormzhang  ·  真正该刺激的是收入 ·  昨天  
鸿洋  ·  一款高效的HarmonyOS工具包 ·  昨天  
鸿洋  ·  Android主线程锁监控的一种方案 ·  5 天前  
鸿洋  ·  Android多渠道打包指南 ·  6 天前  
鸿洋  ·  systemserver进程监控者--wat ... ·  1 周前  
51好读  ›  专栏  ›  安卓开发精选

Android Service的启动过程(上)

安卓开发精选  · 公众号  · android  · 2016-11-08 22:45

正文

(点击上方公众号,可快速关注)


来源:伯乐在线专栏作者 - xuyinhuan

链接:http://android.jobbole.com/85150/

点击 → 了解如何加入专栏作者


刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会阻塞主线程的。长时间就直接ANR了。


我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。


这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。


关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。

启动一个Service只需调用Context的startService方法,传进一个Intent即可。看起来好像很简单的说,那是因为Android为了方便开发者,做了很大程度的封装。那么你真的有去学习过Service是怎么启动的吗?Service的onCreate方法回调前都做了哪些准备工作?


先上一张图大致了解下,灰色背景框起来的是同一个类中的方法,如下图:



那接下来就从源码的角度来分析Service的启动过程。


当然是从Context的startService方法开始,Context的实现类是ContextImpl,那么我们就看到ContextImpl的startService方法即可,如下:


@Override

public ComponentName startService(Intent service) {

    warnIfCallingFromSystemProcess();

    return startServiceCommon(service, mUser);

}


会转到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()), getOpPackageName(), user.getIdentifier());

 

    //代码省略

 

        return cn;

    } catch (RemoteException e) {

        throw new RuntimeException("Failure from system", e);

    }

}


可以看到调用了ActivityManagerNative.getDefault()的startService方法来启动Service,ActivityManagerNative.getDefault()是ActivityManagerService,简称AMS。


那么现在启动Service的过程就转移到了ActivityManagerService,我们关注ActivityManagerService的startService方法即可,如下:


@Override

public ComponentName startService(IApplicationThread caller, Intent service,

        String resolvedType, String callingPackage, int userId)

        throws TransactionTooLargeException {

 

     //代码省略

 

    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, callingPackage, userId);

        Binder.restoreCallingIdentity(origId);

        return res;

    }

}


在上述的代码中,调用了ActiveServices的startServiceLocked方法,那么现在Service的启动过程从AMS转移到了ActiveServices了。


继续跟进ActiveServices的startServiceLocked方法,如下:


ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,

        int callingPid, int callingUid, String callingPackage, int userId)

        throws TransactionTooLargeException {

 

    //代码省略

 

    ServiceLookupResult res =

        retrieveServiceLocked(service, resolvedType, callingPackage,

                callingPid, callingUid, userId, true, callerFg);

 

    //代码省略

 

 

    ServiceRecord r = res.record;

 

    //代码省略

 

    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);

}


在startServiceLocked方法中又会调用startServiceInnerLocked方法,


我们瞧瞧startServiceInnerLocked方法,


ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,

        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {

    ProcessStats.ServiceState stracker = r.getTracker();

    if (stracker != null) {

        stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);

    }

    r.callStart = false;

    synchronized (r.stats.getBatteryStats()) {

        r.stats.startRunningLocked();

    }

    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);

 

    //代码省略

 

    return r.name;

}


startServiceInnerLocked方法内部调用了bringUpServiceLocked方法,此时启动过程已经快要离开ActiveServices了。继续看到bringUpServiceLocked方法。如下:


private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,

        boolean whileRestarting) throws TransactionTooLargeException {

 

        //代码省略

 

        if (app != null && app.thread != null) {

            try {

                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);

                realStartServiceLocked(r, app, execInFg);

                return null;

            }

 

       //代码省略

 

       return null;

}


省略了大部分if判断,相信眼尖的你一定发现了核心的方法,那就是

realStartServiceLocked,没错,看名字就像是真正启动Service。那么事不宜迟跟进去探探吧。如下:


private final void realStartServiceLocked(ServiceRecord r,

        ProcessRecord app, boolean execInFg) throws RemoteException {

 

    //代码省略

 

    boolean created = false;

    try {

 

       //代码省略

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

        throw e;

    }

 

    //代码省略

 

    sendServiceArgsLocked(r, execInFg, true);

 

    //代码省略

 

}


找到了。app.thread调用了scheduleCreateService来启动Service,而app.thread是一个ApplicationThread,也是ActivityThread的内部类。此时已经到了主线程。

那么我们探探ApplicationThread的scheduleCreateService方法。如下:


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

}


对待启动的Service组件信息进行包装,然后发送了一个消息。我们关注这个CREATE_SERVICE消息即可。


public void handleMessage(Message msg) {

 

        //代码省略

 

        case CREATE_SERVICE:

            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");

            handleCreateService((CreateServiceData)msg.obj);

            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

            break;

 

        //代码省略

 

}


在handleMessage方法中接收到这个消息,然后调用了handleCreateService方法,跟进handleCreateService探探究竟:


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(

                "Unable to instantiate service " + data.info.name

                + ": " + e.toString(), e);

        }

    }

 

    try {

        if (localLOGV) Slog.v(TAG, "Creating service " + 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,

                ActivityManagerNative.getDefault());

        service.onCreate();

        mServices.put(data.token, service);

        try {

            ActivityManagerNative.getDefault().serviceDoneExecuting(

                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);

        } catch (RemoteException e) {

            // nothing to do.

        }

    } catch (Exception e) {

        if (!mInstrumentation.onException(service, e)) {

            throw new RuntimeException(

                "Unable to create service " + data.info.name

                + ": " + e.toString(), e);

        }

    }

}


终于击破,这个方法很核心的。一点点分析


接下文


关注「安卓开发精选
看更多精选安卓技术文章
↓↓↓