Android Service的启动过程

本文是《Android进阶解密》的读书笔记。所以,可能不会为大家提供多少帮助,我写本文的目的只是为了自己再学习的时候能够有个印象,为自己提供一个方便。

Service的启动过程分为两个部分,分别是ContextImpl到ActivityManagerService的调用过程和ActivityThread启动Service的过程。

一、ContextImpl到ActivityManagerService的调用过程

我们在Activity中启动Service首先调用startService方法,它在ContextWrapper类中实现,其方法体中仅有一行代码:

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

 现在看一下Context类型的mBase对象指的是什么。在ActivityThread启动Activity的过程中,在ActivityThread的performLaunchActivity方法中调用了createBaseContextForActivity方法创建了ContextImpl类型的上下文对象。然后将创建的上下文对象AppContext传递到了app.attach方法中。看一下createBaseContextForActivity方法中做了什么处理。代码如下:

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        
        // 代码省略。。。

        // 调用createActivityContext创建上下文对象

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

       
        // 代码省略。。。

        return appContext;
    }

由此可以看到,传入到activity.attach方法中的appContext对象是ContextImpl类型的。在Activity类中attach方法内调用了ContextWrapper类的attachBaseContext方法。该方法代码如下:

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }

    // 将传递进来的ContextImpl(继承自Context)类型的base对象赋值给了mBase变量

    mBase = base;
}

因此,mBase具体指代的就是ContextImpl。因此我们的启动Service的过程就是从ContextImpl类开始的。代码如下:

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    // 调用了startServiceCommon方法
    return startServiceCommon(service, false, mUser);
}

代码中可以看出ContextImpl.startService方法中返回了startServiceCommon方法。现在看一下这个方法中做了什么操作。

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());

            // 代码省略。。。

            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

该方法中出现了我们熟悉的ActivityManager.getService().startService(....);代码,熟悉Activity启动过程的应该知道,其实这句代码就会调用到ActivityManagerService中的startService方法。至此,ContextImpl到AMS的调用过程就结束了。其时序图如下:

二、ActivityThread启动Service的过程

经过上一过程,代码逻辑执行到了AMS的startService方法。该方法中调用了ActiveServices的startServiceLocked方法。其代码如下:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1:查找是否有与参数service对应的ServiceRecord
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        // 注释2:得到参数service对应的ServiceRecord
        ServiceRecord r = res.record;

       
        // 代码省略。。。。

        // 注释3
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

注释1处,调用了retrieveServiceLocked方法,其作用是查找是否有与参数service对应的ServiceRecord。其代码实现如下:

private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        
        if (r == null) {
            try {
                
                // 注释1:

                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                
                // 注释2

                r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                   
        }
        if (r != null) {
            
            // 代码省略。。。
            
            // 注释3
            return new ServiceLookupResult(r, null);
        }
        return null;
    }

注释1处,最终会调用到PackageManagerService去获取参数service对应的Service信息。注释2处,将第一步获取到的与参数service对应的Service信息封装到ServiceRecord。注释3处,将ServiceRecord以ServiceLookupResult对象的形式返回到ActiveServices的startServiceLocked方法中。startServiceLocked方法的注释2处,通过注释1处返回的ServiceLookupResult得到参数service对应的ServiceRecord,并将其传入到注释3处的startServiceInnerLocked方法。该方法的代码主要就是调用了bringUpServiceLocked方法,这里就不再展示。直接看一下bringUpServiceLocked方法的代码:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1
       
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;

        if (!isolated) {

            // 注释2

            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
           
            // 注释3

            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);

                    // 注释4

                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
                
            }
        } else {          
            // 。。。。
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
        // 注释5
        if (app == null && !permissionsReviewRequired) {
            // 注释6
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        // 。。。。

        return null;
    }

注释1处,得到ServiceRecord的processName值并赋给procName,其中processName用来描述Service想要在哪个进程中运行,默认是当前进程。注释2处,将procName和Service的uid传入到AMS的getProcessRecordLocked方法中,查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来描述运行的应用程序进程的信息。注释3处的判断表示用来运行Service的应用程序进程存在,此时就会调用注释4处的realStartServiceLocked方法。注释5处的判断表明Service对应的应用程序进程还没有创建,此时便会去调用注释6处的代码。注释6处调用的是AMS的startProcessLocked方法去创建Service对应的应用程序进程。现在我们接着看一下注释4处的realStartServiceLocked方法,其代码如下:

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

        // 注释1

        if (app.thread == null) {
            throw new RemoteException();
        }
        
        try {
            
            // 注释2

            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;
        } finally {
            // 代码省略。。。
        }

       // 代码省略。。。
    }

该方法代码有点多,但是我们需要看的只有两处。注释1,需要注意一下,此时如果Service对应的应用程序进程还未创建就会抛出异常。注释2处,调用了app.thread的scheduleCreateService方法。而app.thread是IApplicationThread类型的,它的实现时ActivityThread的内部类ApplicationThread。该方法代码如下:

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需要的信息封装成了CreateServiceData,通过sendMessage方法向H类发送了一条CREATE_SERVICE的信息。我们直接看H类的handleMessage方法中对CREATE_SERVICE的处理:

private class H extends Handler {

        // 代码省略。。。        

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                
                // 省略代码。。。

                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));

                    // 调用了handleCreateService方法

                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                
            }
            
    }

对CREATE_SERVICE的处理就是调用了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();
        
        // 注释1

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // 注释2
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            //.....
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // 注释3
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 注释4
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 注释5
            service.onCreate();
            // 注释6
            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) {
           // 。。。
        }
    }

该方法做了如上的一些内容。注释1,获取要启动的Service的应用程序的LoadedApk。注释2处,获取类加载器,并根据类加载器来创建Service实例。注释3处,创建Service的上下文环境ContextImpl对象。注释4处,调用service的attach方法来初始化Service,并且将上一步创建的ContextImpl对象context传递进去。Service的该方法中调用了ContextWrapper的attachBaseContext方法,将参数context赋值给了mBase。注释5处调用了service的onCreate生命周期方法,这样Service就启动了。注释6处,将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是以IBinder为key以Service为value的ArrayMap集合。

至此,Service的启动过程就学习完了,最后附上这一过程的时序图就结束本文了。

至此文章就结束了,在这里非常感谢《Android进阶解密》一书的作者。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值