1. 程式人生 > 實用技巧 >startService過程原始碼分析

startService過程原始碼分析

startService過程原始碼分析

一、簡介

Service是Android四大元件之一,service有兩種使用方式分別是startService和bindService,startService方式啟動service之後我們無法控制service,即使呼叫service的元件死亡也不會導致啟動的service死亡。startService方式啟動service後至service死亡鎖經歷的生命週期如下:oncreate—>onstartcommon—>ondestory。本篇文章會分析startService過程原始碼,下篇文章會分析bindService過程原始碼。

二、原始碼分析

我們一般是呼叫ContextWrapper的startService,然後它又呼叫mBase.startService,此處mBase是一個ContextImpl物件。在ContextImpl類的startService方法中又呼叫了startServiceCommon

 //android.content.ContextWrapper
 @Override
 public ComponentName startService(Intent service) {
        return mBase.startService(service);
 }

//ContextImpl.java
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}

startServiceCommon如下所示:

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess(this);
        //1呼叫了AMS的startService方法
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), requireForeground,
                        getOpPackageName(), user.getIdentifier());
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}


在註釋1處通過ActivityManager.getService()獲取AMS的本地代理,然後通過該代理呼叫AMS的startService方法。
下面是獲取ActivityManager.getService()獲取AMS的本地代理的流程,可以看出是通過這是一個單例模式。獲取AMS的方式是通過ServiceManager.getService來獲取一個AMS的binder代理,然後轉化為一個IActivityManager返回。因為AMS和呼叫client在不同程序所以返回的am是一個遠端binder代理。

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };


//IActivityManager.java
private static class Proxy implements android.app.IActivityManager
{
@Override public android.content.ComponentName startService(android.app.IApplicationThread caller, android.content.Intent service, java.lang.String resolvedType, boolean requireForeground, java.lang.String callingPackage, int userId) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.content.ComponentName _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((caller!=null))?(caller.asBinder()):(null)));s
if ((service!=null)) {
_data.writeInt(1);
service.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeString(resolvedType);
_data.writeInt(((requireForeground)?(1):(0)));
_data.writeString(callingPackage);
_data.writeInt(userId);
mRemote.transact(Stub.TRANSACTION_startService, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.content.ComponentName.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

AMS的startService方法如下所示:

//ActivityManagerService.java
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) {
       //1獲取呼叫者的pid和uid
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
           //2、呼叫ActiveServices的startServiceLocked方法
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

AMS的startService方法在註釋1處獲取呼叫者的pid和uid,然後在註釋2處呼叫ActiveServices的startServiceLocked方法並傳入在註釋1處獲取呼叫者的pid和uid。

ActiveServices的startServiceLocked方法如下所示:

//ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
        throws TransactionTooLargeException {
        //1、獲取呼叫程序ProcessRecord,如果為null則丟擲異常
          if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + callingPid
                        + ") when starting service " + service);
            }
            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        }
//2、通過retrieveServiceLocked解析啟動service的intent,並將解析結果放在res.record中
ServiceLookupResult res =
    retrieveServiceLocked(service, resolvedType, callingPackage,
            callingPid, callingUid, userId, true, callerFg, false);
   //解析的serviceRecord為null且permission不為null則判斷返回缺少許可權
  if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        ServiceRecord r = res.record;

//3、呼叫startServiceInnerLocked
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;

}

在註釋1處獲取呼叫程序的ProcessRecord,如果為null則丟擲異常,在註釋2處呼叫retrieveServiceLocked解析啟動service的intent,解析結果包含serviceRecord和啟動該service所需許可權,在註釋3處呼叫startServiceInnerLocked。

startServiceInnerLocked如下所示:

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
//1、呼叫bringUpServiceLocked,注意bringUpServiceLocked函式如果返回非null則表示啟動出錯。
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
    return new ComponentName("!!", error);
}
}

在bringUpServiceLocked中我們來分析service與呼叫者不在同一程序且service所在程序尚未啟動的情況,這是最複雜的情況了。此時會呼叫startProcessLocked啟動
service程序。

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
        //1、如果service所在程序和主執行緒均為非空那麼表示該service已經存在了,直接呼叫其onStartCommand方法
       if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
       //...
        ProcessRecord app;
        if (!isolated) {
            //2、service所在程序已經啟動則直接呼叫realStartServiceLocked啟動service
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        }
       if (app == null && !permissionsReviewRequired) {
        //3、service與呼叫者不在同一程序且service所在程序尚未啟動則呼叫startProcessLocked啟動service程序
         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;
    }
    
    //4、service所在程序還未啟動,將先將這個serviceRecord儲存到mPendingServices中表示等待啟動的service
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
}
}

在註釋1處會先判斷service是否已經啟動過,如果啟動過則直接呼叫其onStartCommand方法,在註釋2處判斷service所在程序是否啟動,如果程序啟動但是service尚未啟動那麼會呼叫realStartServiceLocked啟動service。在註釋3處則是service所在程序未啟動那麼會先啟動service程序,因為程序啟動是非同步的所以在註釋4處會先把service存放到mPendingServices中表示等待啟動的service。

下面我們先來看下service所在程序未啟動的情況,該情況是呼叫startProcessLocked,如下所示:

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
        //呼叫startProcessLocked
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
//呼叫startProcessLocked
startProcessLocked(
        app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);

}

經過呼叫最終是通過startProcessLocked來啟動新的程序

private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
if (entryPoint == null) entryPoint = “android.app.ActivityThread”;
//1、Process.start建立新的程序
startResult = Process.start(entryPoint,
        app.processName, uid, uid, gids, debugFlags, mountExternal,
        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
        app.info.dataDir, invokeWith, entryPointArgs);

}

建立程序過程之前在Android應用程序啟動分析一文中說過,詳細過程請參考 Android應用程序啟動過程.md

建立完新程序之後會呼叫android.app.ActivityThread的main函式,在Android程式中每個程序都有自己的android.app.ActivityThread。至此下面的這些操作都是在新啟動的程序中,呼叫者所在程序已完成它的命令返回了。

//ActivityThread.java
public static void main(String[] args) {

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();
//1、看下attach
thread.attach(false);
Looper.loop();
}


private void attach(boolean system) {
final IActivityManager mgr = ActivityManager.getService();
try {
    //1、呼叫了AMS的attachApplication
    mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
    throw ex.rethrowFromSystemServer();
}
}

在ActivityThread的main函式中會呼叫attach函式,而attach又呼叫了AMS的attachApplication。

AMS的attachApplication函式如下所示:

@Override
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        //1、呼叫attachApplicationLocked
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

在註釋1處呼叫attachApplicationLocked,如下所示:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {
// Find any services that should be running in this process…
if (!badApp) {
    try {
      //1、呼叫ActiveServices的attachApplicationLocked檢視是否有需要啟動的service
        didSomething |= mServices.attachApplicationLocked(app, processName);
        checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
    } catch (Exception e) {
        Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
        badApp = true;
    }
}
}

attachApplicationLocked中我們只關注跟service啟動有關的內容,就是代用attachApplicationLocked檢視是否有需要啟動的service

ActiveServices的attachApplicationLocked如下所示:

boolean attachApplicationLocked(ProcessRecord proc, String processName)
        throws RemoteException {
    boolean didSomething = false;
    // Collect any services that are waiting for this process to come up.
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            //1、mPendingServices中儲存了需要在該程序啟動的service,這裡依次取出並啟動
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }

                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
                        mAm.mProcessStats);
                //2、呼叫realStartServiceLocked啟動service
                realStartServiceLocked(sr, proc, sr.createdFromFg);
                didSomething = true;
                if (!isServiceNeededLocked(sr, false, false)) {
                    // We were waiting for this service to start, but it is actually no
                    // longer needed.  This could happen because bringDownServiceIfNeeded
                    // won't bring down a service that is pending...  so now the pending
                    // is done, so let's drop it.
                    bringDownServiceLocked(sr);
                }
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception in new application when starting service "
                    + sr.shortName, e);
            throw e;
        }
    }
}

在註釋1處取出要啟動的service並在註釋2處呼叫realStartServiceLocked啟動service

realStartServiceLocked如下所示:

private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
 //1、傳送delay訊息
 bumpServiceExecutingLocked(r, execInFg, "create");
  ...
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);
     //2、呼叫ApplicationThread的scheduleCreateService方法
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            app.repProcState);
    r.postNotification();
    created = true;
    ...
    //3、service已經start,呼叫service的onStartCommand
    sendServiceArgsLocked(r, execInFg, true);

}
}

在註釋1處會發送一個延遲處理的訊息SERVICE_TIMEOUT_MSG。在方法scheduleCreateService執行完成,也就是onCreate回撥執行完成之後,便會remove掉該訊息。但是如果沒能在延時時間之內remove該訊息,則會進入執行service timeout流程。註釋2處scheduleCreateService會建立service並回調其onCreate生命週期函式。在註釋3處則回撥用service的onStartCommand。

先來看下bumpServiceExecutingLocked,如下所示

    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
        long now = SystemClock.uptimeMillis();
        if (r.executeNesting == 0) {
            r.executeFg = fg;
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
            }
            if (r.app != null) {
                r.app.executingServices.add(r);
                r.app.execServicesFg |= fg;
                if (r.app.executingServices.size() == 1) {
                    //後臺啟動的服務
                    scheduleServiceTimeoutLocked(r.app);
                }
            }
        } else if (r.app != null && fg && !r.app.execServicesFg) {
            r.app.execServicesFg = true;
             //前臺啟動的服務
            scheduleServiceTimeoutLocked(r.app);
        }
    }

呼叫scheduleServiceTimeoutLocked,如下所示:

    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        //傳送延遲訊息SERVICE_TIMEOUT_MSG
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }

scheduleServiceTimeoutLocked主要任務是傳送延遲訊息SERVICE_TIMEOUT_MSG,針對前後臺service延遲時間會有所不同:

  • 對於前臺服務,則超時為SERVICE_TIMEOUT,即timeout=20s;
  • 對於後臺服務,則超時為SERVICE_BACKGROUND_TIMEOUT,即timeout=200s;

延遲訊息傳送後就會呼叫scheduleCreateService建立service,scheduleCreateService如下所示

//ApplicationThread.java

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;
    //給H傳送了一個message
    sendMessage(H.CREATE_SERVICE, s);
}

//ActivityThread.java
H是ActivityThread的一個內部類,繼承自Handler
public void handleMessage(Message msg) {
switch (msg.what) {
case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, (“serviceCreate: " + String.valueOf(msg.obj)));
    //1、H接收到CREATE_SERVICE的message之後呼叫handleCreateService
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
}
}

scheduleCreateService通過handler傳送了一個CREATE_SERVICE的message,H類收到該訊息後會呼叫handleCreateService進行處理,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.
     //當應用處於後臺即將進行GC,而此時被調回到活動狀態,則跳過本次gc
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        //1、呼叫ClassLoader建立service例項
        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物件
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);
        //如果Application不存在則建立Application物件
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //2、回撥service.attach
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        //3、回撥onCreate()
        service.onCreate();
        mServices.put(data.token, service);
        try {
        //4、
     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);
        }
    }
}

可以看出handleCreateService是真正建立service的地方。在註釋1處通過反射生成service例項在註釋2處呼叫attach,在註釋3處回撥onCreate。在註釋4處呼叫AMS的serviceDoneExecuting方法取消之前傳送service啟動超時的延遲訊息。

之後便是onStartCommand方法的回撥,上面我們在AS的realStartServiceLocked函式中註釋3處呼叫了sendServiceArgsLocked,sendServiceArgsLocked如下所示:

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
            ...
             try {
             //呼叫ApplicationThread的scheduleServiceArgs
            r.app.thread.scheduleServiceArgs(r, slice);
            }
    }
        

ApplicationThread的scheduleServiceArgs如下所示:

   public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
            List<ServiceStartArgs> list = args.getList();

            for (int i = 0; i < list.size(); i++) {
                ServiceStartArgs ssa = list.get(i);
                ServiceArgsData s = new ServiceArgsData();
                s.token = token;
                s.taskRemoved = ssa.taskRemoved;
                s.startId = ssa.startId;
                s.flags = ssa.flags;
                s.args = ssa.args;
                //1、傳送SERVICE_ARGS訊息
                sendMessage(H.SERVICE_ARGS, s);
            }
        }

在註釋1處傳送SERVICE_ARGS訊息,該訊息是在handleServiceArgs函式中處理的,如下所示:

 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) {
                   //呼叫service的onStartCommand
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                }
     }

至此service啟動完畢。

啟動流程:

  1. Process A程序採用Binder IPC向system_server程序發起startService請求;
  2. system_server程序接收到請求後,向zygote程序傳送建立程序的請求;
  3. zygote程序fork出新的子程序Remote Service程序;
  4. Remote Service程序,通過Binder IPC向sytem_server程序發起attachApplication請求;
  5. system_server程序在收到請求後,進行一系列準備工作後,再通過binder IPC向remote Service程序傳送scheduleCreateService請求;
  6. Remote Service程序的binder執行緒在收到請求後,通過handler向主執行緒傳送CREATE_SERVICE訊息;
  7. 主執行緒在收到Message後,通過發射機制建立目標Service,並回調Service.onCreate()方法。

到此,服務便正式啟動完成。當建立的是本地服務或者服務所屬程序已建立時,則無需經過上述步驟2、3,直接建立服務即可。

參考:
startService原始碼分析