Service工作过程(一)——Service启动过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sliverbullets/article/details/81189436
首先,Sevice的工作过程分两种:Service启动过程Service绑定过程
下面是用法:
1.用stratService()启动一个Service
Intent intentService = new Intent(this, MyService.class);
startService(intentService);
2.用bindService()绑定一个Service
Intent intentService = new Intent(this,MyService.calss);
bindService(intentServcie,mSeviceConnection,BIND_AUTOCREATE);

这里有3个参数:第一个是Intent类型,第二个是ServiceConnection类型,第三个是int类型的一个flag。
然后,我们开始分析一下Sevice的两种工作状态的具体过程。

一、Service启动过程

Service的启动过程是从ContextWrapper的startService开始,如下所示:

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

mBase的类型是ContextImpl
这里写图片描述

ContextImpl是一个很重要的数据结构,它是Context的具体实现,而Context是abstract类型。ContextImpl上下文API的通用实现,它提供了基础用于活动和其他应用程序组件的上下文对象。它在Activity启动过程中,通过Activity的attach方法来和Activity建立关联,并在attach方法中完成Window的创建并建立自己和Window的关联,这样当Window接受到外部输入事件后就可以将事件传递给Activity。
它是在activity启动的时候,有一个performLaunchActivity方法,在这个方法中被创建出来的。

从ContentWrapper的实现可以看出,其大部分的操作是通过mBase来实现的,在设计模式中是一种典型的桥接模式,下面继续看ContextImpl的startService方法:
这里写图片描述

//这个是上面方法接着调用的方法startServiceConmmon()
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在ContextImple中,startService方法会调用startServiceCommon方法。StartServiceCommon方法中有一句ComponentName cn = ActivityManager.getService().startService(...);书上原是由AMS对象调用,但是由于AMN要弃用了所以这里不一样了。

———-AMS(ActivityManagerService)和AMN(ActivtyManagerNative)———–
AMN:我在《Android艺术开发探索》书上看时觉得AMN还很重要就看了一下,但这本书的版本是2015年的,现在AMN准备弃用了,可以在as上用这里写图片描述这个搜索框搜索ServiceManagerNative,然后如下所示:
这里写图片描述
AMS:具体看图吧:这里写图片描述

继续上面ActivityManager.getService()是获取一个单例AMS对象。原书上是由AMN.getDefault()方法获取的,现在也改了。
这里写图片描述
AMS对象调用startService()方法,用来启动服务,是一个远程的调用过程。实现如下:

@Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }

        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

service这个对象来完成Service后续的启动过程。

mService对象的类型是ActiveServices,ActiveServices是一个辅助AMS进行Servcie管理的类,包括Service的启动、绑定、停止等。

其中,mServcie调startServiceLocked方法(好长),这个方法尾部会调用startServiceInnnerLocked方法,startServcieInnerLocked的实现如下:

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        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, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }

        if (r.startRequested && addToStarting) {
            boolean first = smap.mStartingBackground.size() == 0;
            smap.mStartingBackground.add(r);
            r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
            if (DEBUG_DELAYED_SERVICE) {
                RuntimeException here = new RuntimeException("here");
                here.fillInStackTrace();
                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
            } else if (DEBUG_DELAYED_STARTS) {
                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
            }
            if (first) {
                smap.rescheduleDelayedStartsLocked();
            }
        } else if (callerFg || r.fgRequired) {
            smap.ensureNotStartingBackgroundLocked(r);
        }

        return r.name;
    }

在上述代码中,ServiceRecord描述的是一个Servcie记录,ServiceRecord一直贯穿整个Service的启动过程。startServiceInnerLocked方法并没有完成具体的启动工作,而是把后续的工作交给了bringUpServiceLocked方法来处理,在bringUpServiceLocked方法中又调用了realStartServiceLocked方法。从名字上来看,这个方法应该是一个真正启动Service的方法。它的实现如下:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        boolean created = false;
        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.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            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;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

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

        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMapLocked(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_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

//app.thread这里我的AS看不到代码
在上述代码中,首先它通过app.thread的scheduleCreateService方法来创建Service对象调用其onCreate,接着再通过sendServiceArgsLocked方法来调用Service的其他方法,如:onStartCommond,这两个过程均属于进程间通信。而app.thread的对象是iAppliacationThread类型,它实际上是一个Binder,因此只需要看ApplicationThread对Service启动过程的处理,通过ApplicationThread类中的scheduleCreateService方法发送一个msg,看代码如下:

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

这里发送了CREATE_SERVICE消息,H(它在ActivityThread.java中)会接收并通过ActivityThread的handleCreateService方法来完成最终Service的启动。

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,
                    ActivityManager.getService());
            service.onCreate();
            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) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

这个方法中:
1.通过类加载器加载创建Service的实例。
2.创建Application对象并调用其onCreate,并且Application的创建过程只有一次。
3.创建conTextImpl对象并通过Service的attach方法建立二者之间的关系,这个过程和Activity实际上是类似的,毕竟Service和Activity都是一个Contex。
4.最后Service调用onCreate方法并将Service对象存储到ActivityThread中的一个列表(Map)中。如下;

final ArrayMap<IBinder,Service> mService = 
                    new ArrayMap<IBinder, Service>()

由于Service的onCreate方法已经被执行了,所以Servcie已经启动了。除此之外,ActivityThread中还会通过hanleServiceArgs方法调用Servcie的onStartCommand方法。(onCreate方法的执行和onStartCommand方法的调用前面已经提到了)

猜你喜欢

转载自blog.csdn.net/sliverbullets/article/details/81189436