zoukankan      html  css  js  c++  java
  • android4.4组件分析--service组件

    6       Service

    6.1            service介绍

    6.1.1.            基本介绍

    Service是Android四大组件之中的一个(其余的是activity、BroadcastReceiver、Content Provider)。

    Service(服务)是一个没实用户界面的在后台执行执行耗时操作的应用组件。其它应用组件可以启动Service。而且当用户切换到另外的应用场景,Service将持续在后台执行。另外。一个组件可以绑定到一个service并与之交互(IPC机制),比如,一个service可能会处理网络操作,播放音乐。操作文件I/O或者与内容提供者(content provider)交互。全部这些活动都是在后台进行。不同应用程序也可以通过service来实现进程间通信(IPC)。

    service不能自己启动执行,它须要通过某一个Activity或者其它Context对象来启动。假设在Service的onCreate或者onStart做一些非常耗时间的事情。最好在 Service里启动一个线程来完毕,由于Service是跑在主线程中,会影响到UI操作或者堵塞主线程中的其它事情。

    官方对Service的定义:

     API Guides:Services

      http://developer.android.com/guide/components/services.html

       API Guides:Bound Services  http://developer.android.com/guide/components/bound-services.html

    6.1.2.    service的生命周期

    Service的生命周期图:



    service的生命周期,从它被创建開始。到它被销毁为止。依据启动方式不同,

    能够有两条不同的路径:

    通过startService()启动

    被开启的service通过其它组件调用 startService()被创建。这样的service能够无限地执行下去。必须调用stopSelf()方法或者其它组件调用stopService()方法来停止它。当service被停止时。系统会销毁它。

     通过bindService()启动

        被绑定的service是当其它组件(一个客户)调用bindService()来创建的。

      客户能够通过一个IBinder接口和service进行通信。客户能够通 unbindService()方法来关闭这样的连接。

      一个service能够同一时候和多个客户绑定。当多个客户都解除绑定之后。系统会销毁service。 这两条路径并非全然分开的。即是说,你能够和一个已经调用了 startService()而被开启的service进行绑定。

    service总体的生命时间是从onCreate()被调用開始,到onDestroy()方法返回为止。和activity一样,service在onCreate()中进行它的初始化工作。在onDestroy()中释放残留的资源。

    service活动的生命时间(active lifetime)是从onStartCommand() 或onBind()被调用開始,

    它们各自处理由startService()或 bindService()方法传过来的Intent对象。

    假设service是被开启的,那么它的活动生命周期和整个生命周期一同结束。

    假设service是被绑定的。它们它的活动生命周期是在onUnbind()方法返回后结束。

    6.1.3.    service的启动方式

    有了 Service 类我们怎样启动他呢,通常有两种方法:

    • Context.startService()

    • Context.bindService() 

    Ps:跨进程通信:AIDL。这也能够启动服务。

    使用context.startService() 启动Service

    其生命周期为context.startService() ->onCreate()- >onStart()->Service running-->(假设调用context.stopService() )->onDestroy() ->Service shut down

    假设Service还没有执行,则android先调用onCreate()然后调用onStart()
    假设Service已经执行。则仅仅调用onStart(),所以一个ServiceonStart方法可能会反复调用多次。

     

    调用stopService的时候直接onDestroy
    假设是调用者自己直接退出而没有调用stopService的话。Service会一直在后台执行。
    Service的调用者再启动起来后能够通过stopService关闭Service

    所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy

    使用bindService()启动Service
    context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop

    onBind
    将返回给client一个IBind接口实例,IBind同意client回调服务的方法,比方得到Service执行的状态或其它操作。这个时候把调用者(Context。比如Activity)会和Service绑定在一起。Context退出了,Srevice就会调用onUnbind->onDestroy对应退出。

     

     

    所以调用bindService的生命周期为:onCreate --> onBind(仅仅一次,不可多次绑定) --> onUnbind --> onDestory。一但销毁activity它就结束,假设按home把它放到后台。那他就不退出。

     

    PSService每一次的开启关闭过程中,仅仅有onStart可被多次调用(通过多次startService调用),其它onCreateonBindonUnbindonDestory在一个生命周期中仅仅能被调用一次。

    6.1.4.    其它方面

    提高 Service 优先级 

    Android 系统对于内存管理有自己的一套方法。为了保障系统有序稳定的执行,

    系统内部会自己主动分配,控制程序的内存使用。当系统觉得当前的资源很有限的时候,为了保 证一些优先级高的程序能执行,就会杀掉一些他觉得不重要的程序或者服务来释放内存。

    这样就能保证真正对用户实用的程序仍然再执行。

    假设你的 Service 碰上了这样的情况,多半会先被杀掉。

    但假设你添加 Service 的优先级就能让他多留一会,我们能够用 setForeground(true) 来设置 Service 的优先级。

    为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前执行的 Activity 一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在执行的 Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉。仅仅是提高了他的优先级。

    设置 Service 訪问空间 

    在应用声明service的manifest文件中面,声明service的时候。设置其exported属性,能够控制service被安全訪问。

    6.2            代码分析

    6.1.1.    startService

        从前面的介绍我们知道,启动一个service能够使用startService()来实现,我们现来分析startService的代码实现。

    6.1.1.1.      阶段一:应用调用startService()

    启动service比較常见的是通过activity来启动,在activity里面调用startService

    是怎样实现的呢?

    首先,我们看以下的关系图,



    Context

    抽象类。定义了一些全局常量和应用环境抽象方法。

      ContextWrapper

    类。继承了Context,实现了父类方法,方法全都以类构建的时候传入的Context实例为基础实现,通过使用子类的实例,子类就能够不用重写很多函数。

        ContextThemeWrapper

    类。继承了ContextWrapper,添加了theme相关的方法。

    也是使用传入的Context实例为基础实现。

          Activity

    类。继承了ContextThemeWrapper,作为应用窗体界面的父类,维护相关显示和交互功能。

        Application

    类,继承了ContextWrapper,维护应用信息。

        Service

    抽象类,继承了ContextWrapper,

     

     

      ContextImpl

    类。继承了Context,实现了父类方法,是Context类的真正实现之处。

    它为activity、service、application提供了context实例。

        能够看到,Activity继承自Context,ContextImpl是Context类的真正实现之处,所以在Activity里面调用startService。实际是在ContextImpl里运行,

        public ComponentName startService(Intent service) {

            warnIfCallingFromSystemProcess();

            return startServiceCommon(service, mUser);

        }

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

    这里通过ActivityManagerNative获取到IActivityManager的实例。实际就是AMS的远程接口。使用Binder方式。调用AMS的startService方法,

         public ComponentName startService(IApplicationThread caller, Intent service,

                String resolvedType, int userId) throws RemoteException

        {

            Parcel data = Parcel.obtain();

            Parcel reply = Parcel.obtain();

            data.writeInterfaceToken(IActivityManager.descriptor);

            data.writeStrongBinder(caller != null ? caller.asBinder() : null);

            service.writeToParcel(data, 0);

            data.writeString(resolvedType);

            data.writeInt(userId);

            mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);

            reply.readException();

            ComponentName res = ComponentName.readFromParcel(reply);

            data.recycle();

            reply.recycle();

            return res;

        }

             參数caller是一个ApplicationThread实例。它是在ActivityThread里通过ApplicationThread mAppThread = new ApplicationThread();创建的,ApplicationThread继承自ApplicationThreadNative。间接继承自Binder,在Android应用程序中。每个进程都用一个ActivityThread实例来表示,而在ActivityThread类中,成员变量mAppThread,它是一个ApplicationThread实例。实现了IApplicationThread接口,它的作用是用来辅助ActivityThread类来运行一些操作,这几者之间的相互关系见专门的章节。

    參数service是一个Intent实例,它里面指定了要启动的服务的名称,就是我们在创建intent的时候使用的名称。

            參数resolvedType是一个字符串。String类型,它表示service这个IntentMIME类型,它是在解析Intent时用到的。

    通过service.resolveTypeIfNeeded()获取到。      

    6.1.1.2.      阶段二:AMS运行startService

       在AMS里面。startService的实现例如以下,

         public ComponentName startService(IApplicationThread caller, Intent service,

                String resolvedType, int userId) {

    enforceNotIsolatedCaller("startService");

            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;

            }

        }

    通过binder传递,调用到该方法,并解析出相关參数。当中,service是应用发起的intent,mServices是AMS里面定义的一个ActiveServices实例引用,其方法startServiceLocked经过參数推断和转化后,继续调用startServiceInnerLocked。进一步到bringUpServiceLocked,

    当中在startService里,enforceNotIsolatedCaller("startService");用来推断应用是否被隔离。假设是。则抛出异常,推断方法是通过UID获取到APPID(APPID=UID%100000)。再推断APPID是否在隔离沙箱定义的UID范围之内(99000-99999),是的话就觉得是被隔离的应用,不同意启动服务。

    通常APPID值是在10000到19999之间的。

    ActiveServices类是AMS的辅助类,完毕。其成员变量mAm相应的就是一个AMS的实例,ActiveServices的startServiceLocked主要代码例如以下,

         ComponentName startServiceLocked(IApplicationThread caller,

                Intent service, String resolvedType,

                int callingPid, int callingUid, int userId) {

    //获取进程的执行状态

                final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

    callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;

    //新建一个ServiceLookupResult容器 。并创建ServiceRecord

            ServiceLookupResult res =

                retrieveServiceLocked(service, resolvedType,

                        callingPid, callingUid, userId, true, callerFg);

    // record为空会返回

            if (res.record == null) {

                return new ComponentName("!", res.permission != null

                        ? res.permission : "private to package");

            }

            ServiceRecord r = res.record;

    //填充ServiceRecord的初始状态

            r.lastActivity = SystemClock.uptimeMillis();

            r.startRequested = true;

            r.delayedStop = false;

            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),

                    service, neededGrants));

            if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {

    }

    //继续进一步调用

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

    mAm.getRecordForAppLocked通过IApplicationThread获取到其相应的进程信息,当前执行进程的信息都存放在ProcessRecord里面。通过进程信息,推断当前进程是前台进程还是后台进程,设置callerFg标识,供后面启动service处理。

        retrieveServiceLocked 会根据userid新建一个ServiceMap,里面存放service的相关信息,再根据service的訪问权限和manifest里设置的exported属性,创建不同的ServiceLookupResult并返回,ServiceLookupResult的ServiceRecord类型成员record是ServiceRecord类型,存放的就是将要启动的service的状态信息,创建这个实例后,后面就開始初始状态。

    假设record为null,会返回。

    兴许的代码对ServiceRecord进行初始填充。

    startServiceInnerLocked处理逻辑比較简单,主要是调用bringUpServiceLocked,再依据callerFg标识。处理服务的后台属性,主要代码例如以下,

         ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,

                ServiceRecord r, boolean callerFg, boolean addToStarting) {

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

                smap.ensureNotStartingBackground(r);

    }

    而bringUpServiceLocked的代码例如以下,

        private final String bringUpServiceLocked(ServiceRecord r,

                int intentFlags, boolean execInFg, boolean whileRestarting) {

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

                sendServiceArgsLocked(r, execInFg, false);

                return null;

            }

     …

            // Service is now being launched, its package can't be stopped.

            try {

                AppGlobals.getPackageManager().setPackageStoppedState(

                        r.packageName, false, r.userId);

                app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);

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

                    try {

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

                        realStartServiceLocked(r, app, execInFg);

                        return null;

    }}

            if (app == null) {

                if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,

                        "service", r.name, false, isolated, false)) == null) {

    }}

    能够看出,ServiceRecord类型的变量r在创建过程中并没有初始化app成员变量,所以不会运行sendServiceArgsLocked并返回。而是继续向下运行,当设置好包状态后,会通过AMS获取到启动应用的app实例,进而运行realStartServiceLocked,

    realStartServiceLocked代码例如以下。

        private final void realStartServiceLocked(ServiceRecord r,

                ProcessRecord app, boolean execInFg) throws RemoteException {

            app.services.add(r);

            bumpServiceExecutingLocked(r, execInFg, "create");

            mAm.updateLruProcessLocked(app, true, false);

                app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

                app.thread.scheduleCreateService(r, r.serviceInfo,

                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),

                        app.repProcState);

                r.postNotification();

                created = true;

            requestServiceBindingsLocked(r, execInFg);

            sendServiceArgsLocked(r, execInFg, true);

    }

    在realStartServiceLocked里面,有两个关键的流程,

    一个是app.thread.scheduleCreateService的运行。它发送一个创建服务的CREATE_SERVICE消息出去,当消息被运行的时候,服务类被创建。service的Oncreate()方法被运行,后面我们会具体分析。

    还有一个是sendServiceArgsLocked。它会调用 scheduleServiceArgs,后者也会发出一个消息。当消息被运行时。service的Onstart()方法被运行。

    6.1.1.3.      第三阶段:Service创建和Oncreate()运行

    scheduleCreateService 的功能是发送一个创建服务的CREATE_SERVICE消息出去,当这个消息被处理时,会进行服务类的创建。

    在ActivityThread.java的handleMessage里,会处理CREATE_SERVICE消息。处理的方法为handleCreateService,它会创建一个service实例。在service实例创建的时候,new一个ContextImpl。并调用init进行初始化,

        private void handleCreateService(CreateServiceData data) {

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

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

                ContextImpl context = new ContextImpl();

                context.init(packageInfo, null, this);

                Application app = packageInfo.makeApplication(false, mInstrumentation);

                context.setOuterContext(service);

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

    ContextImpl实例的内部的创建步骤例如以下:

    ContextImpl有例如以下一些重要的变量。其类型和函数说明例如以下,

    LoadedApk mPackageInfo   服务相应的包信息。

    ActivityThread mMainThread  启动服务的应用相应的ActivityThread,

    Context mOuterContext 服务相应的ContextImpl所关联的Context。就是要创建的服务实例。

    UserHandle mUser 应用进程UID相应的UserHandle,

       它另一个SYSTEM_SERVICE_MAP的hashMap。通过registerService。用来存放系统服务的接口实例,这个数组的初始化过程在static语句块里面。

        private static void registerService(String serviceName, ServiceFetcher fetcher) {

            if (!(fetcher instanceof StaticServiceFetcher)) {

                fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;

            }

            SYSTEM_SERVICE_MAP.put(serviceName, fetcher);

        }

        static {

            registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {

                    public Object getService(ContextImpl ctx) {

                        return AccessibilityManager.getInstance(ctx);

                    }});

            registerService(CAPTIONING_SERVICE, new ServiceFetcher() {

                    public Object getService(ContextImpl ctx) {

                        return new CaptioningManager(ctx);

                    }});

            registerService(ACTIVITY_SERVICE, new ServiceFetcher() {

                    public Object createService(ContextImpl ctx) {

                        return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());

                    }});

     对于ContextImpl实例的创建。除了以下的初始化函数外,依据类的创建过程,也包括上面静态语句块的运行。

        ContextImpl() {

            mOuterContext = this;

        }

    ContextImpl.init的目的就是完毕上面提到过的基本的成员变量的初始化。让使用这个类的方法能使用相关类提供的服务。

        final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,

                Resources container, String basePackageName, UserHandle user) {

            mPackageInfo = packageInfo;

            mResources = mPackageInfo.getResources(mainThread);

            mResourcesManager = ResourcesManager.getInstance();

            mMainThread = mainThread;

            mActivityToken = activityToken;

            mContentResolver = new ApplicationContentResolver(this, mainThread, user);

            mUser = user;

    }

    mMainThread就是创建服务的应用相应的ActivityThread,

    packageInfo 就是要创建的服务类的包信息。

    mUser 相应于Process.myUserHandle()。

    对于service。还要将mOuterContext设置为service的实例。

     context.setOuterContext(service);

        final void setOuterContext(Context context) {

            mOuterContext = context;

        }

    创建服务的时候,还须要获取到一个Application实例。对于同一个包,公用一个应用,在第一次启动应用时,须要创建一个应用。应用相同也要新建一个ContextImpl实例。并与之关联起来,

        public Application makeApplication(boolean forceDefaultAppClass,

                Instrumentation instrumentation) {

            if (mApplication != null) {

                return mApplication;

            }

                java.lang.ClassLoader cl = getClassLoader();

                ContextImpl appContext = new ContextImpl();

                appContext.init(this, null, mActivityThread);

                app = mActivityThread.mInstrumentation.newApplication(

                        cl, appClass, appContext);

                appContext.setOuterContext(app);

            mActivityThread.mAllApplications.add(app);

            mApplication = app;

            if (instrumentation != null) {

                try {

                    instrumentation.callApplicationOnCreate(app);

    …   

    service.attach的目的就是在创建service实例后,把service里一些关键的成员变量初始化。和关联类相互关联起来,如context、mThread、mApplication、mActivityManager,

        public final void attach(

                Context context,

                ActivityThread thread, String className, IBinder token,

                Application application, Object activityManager) {

            attachBaseContext(context);

            mThread = thread;           // NOTE:  unused - remove?

            mClassName = className;

            mToken = token;

            mApplication = application;

            mActivityManager = (IActivityManager)activityManager;

            mStartCompatibility = getApplicationInfo().targetSdkVersion

                    < Build.VERSION_CODES.ECLAIR;

        }

    之后,便開始运行service的onCreate()方法了,service类本身是一个抽象类,其onCreate类就须要子类自行实现了。

    6.1.1.4.      第四阶段:Onstart()方法被运行

    如前所述,在sendServiceArgsLocked会调用r.app.thread.scheduleServiceArgs(),

    后者会发送一个SERVICE_ARGS消息。这个消息会被ActivityThread.java的handleMessage方法处理,详细处理方法则为handleServiceArgs,

         private void handleServiceArgs(ServiceArgsData data) {

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

                    if (data.args != null) {

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

                    }

                    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, 1, data.startId, res);

                    } catch (RemoteException e) {

                        // nothing to do.

                    }

                    ensureJitEnabled();

    }

    当中onStartCommand会调用onStart()方法。相同,因为service是抽象类。所以会运行到用户自己定义的类。

    至此,service的启动过程分析完毕。上面仅仅是分析了其启动的主流程,而实际上,因为各种不同的状态。其启动过程比这复杂非常多。

    6.1.1.5.      总结StartService启动流程

    综上所述。Service的启动流程例如以下:



  • 相关阅读:
    streamsets 集成 cratedb 测试
    streamsets k8s 部署试用
    streamsets rest api 转换 graphql
    StreamSets sdc rpc 测试
    StreamSets 相关文章
    StreamSets 多线程 Pipelines
    StreamSets SDC RPC Pipelines说明
    StreamSets 管理 SDC Edge上的pipeline
    StreamSets 部署 Pipelines 到 SDC Edge
    StreamSets 设计Edge pipeline
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5118351.html
Copyright © 2011-2022 走看看