1. 程式人生 > >Service啟動過程分析

Service啟動過程分析

Service是一種計算型元件,用於在後臺執行一系列的計算任務。由於工作在後臺,因此使用者是無法直接感知到它的存在。Service元件和Activity元件略有不同,Activity元件只有一種執行模式,即Activity處於啟動狀態,但是Service元件卻有兩種狀態:啟動狀態和繫結狀態。當Service元件處於啟動狀態時,這個時候Service內部可以做一些後臺計算,並且不需要和外界有直接的互動。

Service分為兩種工作狀態,一種是啟動狀態,主要用於執行後臺計算,另一張是繫結狀態,主要用於其他元件和Service的互動,需要注意的是Service的這兩種狀態是可以共存的,即Service既可以處於啟動狀態也可以同時處於繫結狀態。

Service的啟動過程

Service的啟動過程從ContextWrapper的startService開始。

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

這裡的mBase的型別是ContextImpl,其實說到這,就得說下Activity被建立時會通過attach方法將一個ContextImpl物件關聯起來,這也就是mBase。從ContextWrapper的實現可以看出,其中大部分操作都是通過mBase來實現的,在設計模式中這是一種典型的橋接模式。

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, mUser);
    }

   private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), 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());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
       

從startServiceCommon方法中可以看出,是ActivityManagerNative.getDefault()這個方法的類啟動的,其實ActivityManagerNative.getDefault()就是AMS,是通過AMS來啟動服務的行為是一個遠端過程呼叫。

    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, 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);
        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;
        }
    }

在上面的程式碼中,AMS會通過mServices這個物件來完成Service後續的啟動過程,mServices物件的型別是ActiveService,ActiveService是一個輔助AMS進行Service管理的類,包括Service的啟動、繫結和停止等。

最終是通過app.thread的scheduleCreateService方法來建立Service物件並呼叫onCreate,接著再通過sendServiceArgsLocked方法來呼叫Service的其他方法,比如onStartCommand,這兩個過程均是程序間通訊,到最後是通過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);
        }

是通過發訊息給Handler H,H會接收這個CREATE_SERVICE訊息並通過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,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().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);
            }
        }
    }

handleCreateService主要完成了如下幾件事:

  • 通過類載入器建立Service的例項
  • 建立Application物件並呼叫其onCreate,當然Application的建立過程只會有一次。
  • 接著建立ConTextImpl物件並通過Service的attach方法建立二者之間的關係。
  • 最後呼叫onCreate方法,並將Service物件儲存到ActivityThreadd的一個列表中。

Service的繫結過程

和Service的啟動過程一樣,Service繫結過程也是從ContextWrapper開始的。

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

然後會呼叫bindServiceCommon方法,這個方法主要完成如下兩件事情:

  • 首先將客戶端的ServiceConnection物件轉化為ServiceDispatcher.InnerConnection物件。
  • 接著bindServiceCommon會通過AMS來完成Service的具體繫結過程,對應於AMS的bindService方法。

最終也是呼叫handleBindService來處理。

private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

最後,以借用一張流程圖來說明:
啟動流程圖

閱讀擴充套件