专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
鸿洋  ·  Google 为何设计了如此难用的 ... ·  昨天  
stormzhang  ·  真正该刺激的是收入 ·  3 天前  
鸿洋  ·  一款高效的HarmonyOS工具包 ·  3 天前  
鸿洋  ·  Android主线程锁监控的一种方案 ·  1 周前  
stormzhang  ·  打工人维权,难吗? ·  1 周前  
51好读  ›  专栏  ›  安卓开发精选

Android Service的启动过程(下)

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

正文

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


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

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

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


接上文


首先获取到一个LoadedApk对象,在通过这个LoadedApk对象获取到一个类加载器,通过这个类加载器来创建Service。如下:


java.lang.ClassLoader cl = packageInfo.getClassLoader();

service = (Service) cl.loadClass(data.info.name).newInstance();


接着调用ContextImpl的createAppContext方法创建了一个ContextImpl对象。


之后再调用LoadedApk的makeApplication方法来创建Application,这个创建过程如下:


public Application makeApplication(boolean forceDefaultAppClass,

        Instrumentation instrumentation) {

    if (mApplication != null) {

        return mApplication;

    }

 

    Application app = null;

 

    String appClass = mApplicationInfo.className;

    if (forceDefaultAppClass || (appClass == null)) {

        appClass = "android.app.Application";

    }

 

    try {

        java.lang.ClassLoader cl = getClassLoader();

        if (!mPackageName.equals("android")) {

            initializeJavaContextClassLoader();

        }

        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

        app = mActivityThread.mInstrumentation.newApplication(

                cl, appClass, appContext);

        appContext.setOuterContext(app);

    } catch (Exception e) {

        if (!mActivityThread.mInstrumentation.onException(app, e)) {

            throw new RuntimeException(

                "Unable to instantiate application " + appClass

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

        }

    }

    mActivityThread.mAllApplications.add(app);

    mApplication = app;

 

    if (instrumentation != null) {

        try {

            instrumentation.callApplicationOnCreate(app);

        } catch (Exception e) {

            if (!instrumentation.onException(app, e)) {

                throw new RuntimeException(

                    "Unable to create application " + app.getClass().getName()

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

            }

        }

    }

 

    // Rewrite the R 'constants' for all library apks.

    SparseArray packageIdentifiers = getAssets(mActivityThread)

            .getAssignedPackageIdentifiers();

    final int N = packageIdentifiers.size();

    for (int i = 0; i N; i++) {

        final int id = packageIdentifiers.keyAt(i);

        if (id == 0x01 || id == 0x7f) {

            continue;

        }

 

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);

    }

 

    return app;

}


当然Application是只有一个的,从上述代码中也可以看出。


在回来继续看handleCreateService方法,之后service调用了attach方法关联了ContextImpl和Application等


最后service回调了onCreate方法,


service.onCreate();

mServices.put(data.token, service);


并将这个service添加进了一个了列表进行管理。


至此service启动了起来,以上就是service的启动过程。


你可能还想要知道onStartCommand方法是怎么被回调的?可能细心的你发现了在ActiveServices的realStartServiceLocked方法中,那里还有一个sendServiceArgsLocked方法。是的,那个就是入口。


那么我们跟进sendServiceArgsLocked方法看看onStartCommand方法是怎么回调的。


private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,

        boolean oomAdjusted) throws TransactionTooLargeException {

    final int N = r.pendingStarts.size();

 

        //代码省略

 

        try {

 

        //代码省略

 

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

        } catch (TransactionTooLargeException e) {

            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="

                    + si.intent);

            caughtException = e;

        } catch (RemoteException e) {

            // Remote process gone...  we'll let the normal cleanup take care of this.

            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);

            caughtException = e;

        }

 

        //代码省略

}


可以看到onStartCommand方法回调过程和onCreate方法的是很相似的,都会转到app.thread。那么现在就跟进ApplicationThread的scheduleServiceArgs。

你也可能猜到了应该又是封装一些Service的信息,然后发送一个消息, handleMessage接收。是的,源码如下:


public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,

    int flags ,Intent args) {

    ServiceArgsData s = new ServiceArgsData();

    s.token = token;

    s.taskRemoved = taskRemoved;

    s.startId = startId;

    s.flags = flags;

    s.args = args;

 

    sendMessage(H.SERVICE_ARGS, s);

}


public void handleMessage(Message msg) {

 

        //代码省略

 

        case SERVICE_ARGS:

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

            handleServiceArgs((ServiceArgsData)msg.obj);

            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

            break;

 

        //代码省略

}


咦,真的是这样。谜底应该就在handleServiceArgs方法了,那么赶紧瞧瞧,源码如下:


private void handleServiceArgs(ServiceArgsData data) {

    Service s = mServices.get(data.token);

    if (s != null) {

        try {

            if (data.args != null) {

                data.args.setExtrasClassLoader(s.getClassLoader());

                data.args.prepareToEnterProcess();

            }

            int res;

            if (!data.taskRemoved) {

                res = s.onStartCommand(data.args, data.flags, data.startId);

            } else {

                s.onTaskRemoved(data.args);

                res = Service.START_TASK_REMOVED_COMPLETE;

            }

 

            QueuedWork.waitToFinish();

 

            try {

                ActivityManagerNative.getDefault().serviceDoneExecuting(

                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);

            } catch (RemoteException e) {

                // nothing to do.

            }

            ensureJitEnabled();

        } catch (Exception e) {

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

                throw new RuntimeException(

                        "Unable to start service " + s

                        + " with " + data.args + ": " + e.toString(), e);

            }

        }

    }

}


可以看到回调了onStartCommand方法。


以上就是Service的启动过程的源码分析。


从中,我理解了Service的启动过程的同时,阅读源码的能力也提高了,分析源码的时候我没能力把每一个变量,每一个方法都搞懂,我关注的都是一些关键的字眼,比如这篇文章就是start呀,service呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。


这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。


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