從源碼出發深入理解 Android Service

dsgfjuyjd 8年前發布 | 11K 次閱讀 安卓開發 Android開發 移動開發

本文是 Android 系統學習系列文章中的第三章節的內容,介紹了 Android Service 相關的基礎知識,然后從源碼的角度上分析 Service 的一些實現原理。

0X00 Service 基礎知識

Service 作為 Android 提供的四大組件之一,主要負責一些沒有前臺顯示的后臺任務。即使應用本身不再可見,Service 的屬性也能使得其在后臺運行。除此之外,Service 也可以通過 Binder 機制,與界面甚至其他應用進行進程間通信,以實現相應的交互。這里需要簡單說明的是,既然是后臺任務,為什么不選用 Thread 了?選用 Service 和 Thread 的主要區別在于需不需要在應用不可見的時候依然保留。舉例來說,新聞詳情頁面的數據請求,只用在當前頁面生效,而音樂播放這些后臺任務就可以通過 Service 的方式來實現。

關于如何使用 Service,官方教程已經說明得足夠詳細了,如果對這些用法,還有不清晰的地方,請戳這里進行查看,-> 官方教程 。官方教程里面包括,startService 和 bindService 的區別,在不同場景下應該選用哪種 Service 實現方式。

Service 生命周期

0X01 startService 調用流程

從前面的教程里面,可以知道 Service 的啟動一般有兩種方式,分別是 bindService 和 startService。這里主要說明 startService, 具體的實現邏輯在 ContextImpl 中,我們看看源碼是怎么實現的。

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

接下來,看看方法內部具體是怎么實現的。

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess();
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());
        // ignore some codes...
        return cn;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

從上面的代碼可以看到,這里是通過 ActivityManagerNative 來執行的。可能會覺得很熟悉。事實上這里采用的機制就是同樣的。

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

ActivityManagerNative 的 getDefault 方法是這么實現的。可以看到,gDefault 是類型為 IActivityManager 的 Binder 對象。而這個 Binder 對象可以看做是在 System Server 中的 ActivityManagerService 的句柄,通過這個 Binder 對象,可以跨進程調用 ActivityManagerService。

如果上述內容不容易理解的話,我們可以類比地來看這個問題。我們遙控電視的時候,例如進行增加音量的操作,這個操作實際不是由遙控器完成的,而是電視中的電子元件完成的。遙控器會和電視進行協商,先聲明有哪些操作可以執行,然后將這些協商后的操作在遙控器端和電視端 ?? 都實現,區別在于電視機是真的實現,而遙控器只是發送操作指令而已。前面代碼中提及的 gDefault 就是 ActivityManagerService 的遙控器。

電視遙控器

接著往下看看電視端是具體怎么操作的,這里的電視端就是 ActivityManagerService.

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, String callingPackage, int userId)
        throws TransactionTooLargeException {
    enforceNotIsolatedCaller("startService");

    // ignore some codes...

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

看起來具體的邏輯,都在類型為 ActiveServices 的 mServices 對象中。ActiveServices 是 AMS 專門用來管理 Service 的類,大部分和 Services 相關的邏輯都在這里面。

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, String callingPackage, int userId)
        throws TransactionTooLargeException {
    if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
            + " type=" + resolvedType + " args=" + service.getExtras());

    // 調用進程的優先級是否足夠
    final boolean callerFg;
    if (caller != null) {
        // 能否找到相應的 Process
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + Binder.getCallingPid()
                    + ") when starting service " + service);
        }
        callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
    } else {
        callerFg = true;
    }

    // ignore some codes.

    final ServiceMap smap = getServiceMap(r.userId);
    boolean addToStarting = false;
    if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
            // 避免同時有多個服務啟動時,造成的性能問題,如果超過閾值后,就進行延遲
            if (r.delayed) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
                return r.name;
            }
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                // Something else is starting, delay!
                Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
            addToStarting = true;
        } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
            addToStarting = true;
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                    "Not delaying, but counting as bg: " + r);
        }
    }

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

可以看到 startServiceLocked 主要進行了權限校驗和為性能進行的調度,具體的邏輯,還在 startServiceInnerLocked 方法里面。

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ProcessStats.ServiceState stracker = r.getTracker();
    if (stracker != null) {
        // 跟蹤 Service 內存試用狀況
        stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
    }
    r.callStart = false;
    synchronized (r.stats.getBatteryStats()) {
        // 跟蹤電池占用情況
        r.stats.startRunningLocked();
    }
    // 實際啟動 Service
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, 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() + 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.rescheduleDelayedStarts();
        }
    } else if (callerFg) {
        smap.ensureNotStartingBackground(r);
    }

    return r.name;
}

接下來看看 bringUpServiceLocked 是如何實現的,這里就是實際啟動 Service 的地方。

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting) throws TransactionTooLargeException {

    if (r.app != null && r.app.thread != null) {
        // 目標Service已經啟動
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    if (!whileRestarting && r.restartDelay > 0) {
        // 正在重啟,或者等待重啟,直接返回
        return null;
    }

    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);

    // 從重啟 Service 列表中移除
    if (mRestartingServices.remove(r)) {
        // 重試計數
        r.resetRestartCounter();
        clearRestartingIfNeededLocked(r);
    }

    // 移除 delayed 的標示
    if (r.delayed) {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
        getServiceMap(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

    // Service 即將被啟動,它所屬的Package不能被停止
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                r.packageName, false, r.userId);
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        Slog.w(TAG, "Failed trying to unstop package "
                + r.packageName + ": " + e);
    }

    // isolated 變量主要是用于如下問題
    // Service 可以通過 AndroidManifest 中的指令指定在單獨的進程上運行
    // 啟動這個單獨的進程,是一個耗時的過程,因而 isolated 標記起來后,
    // 可以避免在這個過程中又創建了一個進程
    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                    + " app=" + app);
        // 如果應用進程已經創建,而且 Looper 線程已經準備完畢
        // 那么就調用 realStartServiceLocked 實際啟動 Service
        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);
            }

        }
    } else {
        app = r.isolatedProc;
    }

    // 應用進程還未創建,這里需要先啟動應用進程
    if (app == null) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                "service", 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;
        }
    }


    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }

    if (r.delayedStop) {
        // 準備停止 Service
        r.delayedStop = false;
        if (r.startRequested) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                    "Applying delayed stop (in bring up): " + r);
            stopServiceLocked(r);
        }
    }

    return null;
}

上面的代碼較為復雜,這里進行下初步的總結。首先判斷服務是否已經啟動,或者正在重啟中,則直接返回。其后,當前 Service 進程正在啟動中,也直接返回。最后判斷應用進程是否啟動,如果沒有啟動進程,則先啟動進程。

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    // 如果主進程不存在,拋出異常
    if (app.thread == null) {
        throw new RemoteException();
    }

    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);
    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();
        }
        // 確保 Package Opt 工作完成
        mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        // 通過 app.thread 的 binder 對象,通過創建目標 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);
            }
        }
    }

    // 如果是通過 bindService 來執行的,這里就會通知客戶端.
    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));
    }

    // 通知調用 onStartCommand 接口
    sendServiceArgsLocked(r, execInFg, true);

    if (r.delayed) {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
        getServiceMap(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 , 這個 IApplicationThread 對象同樣也是一個 Bindle 接口,與前文提交的 gDefault 不同之處在于兩者的方向是相反的。前者是應用進程操作AMS,而后者則是AMS操作應用進程。IApplicationThread 對應的實現是 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);
}

原來還是通過 mH Handler 這種方式來執行的呀,這與前面文章提及的知識是完全一樣的。在 Handler 中的 handleMessage 是如何處理 CREATE_SERVICE 這個消息的?

case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

繼續看 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();

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

方法實現相對簡單,首先通過 ClassLoader 加載相關的 class 對象,然后將 Service 和 Application 綁定在一起,最后調用 Service 的 onCreate 方法。到此為止,Service 就完全啟動了。

如果使用 Service 的方式是 startService,那么在 Service 啟動后,就可以執行 sendServiceArgsLocked 方法,從而在 Service 的 onStartCommand 里面可以執行相應的后臺代碼,需要特別說明的是,這個是執行在 UI 線程上的,因而建議不要執行耗時的任務,如果是耗時的任務,需要通過多線程的方式來避免主線程的阻塞。即使應用當前不在前臺,阻塞 UI 線程,也是很不好的情況。

我們看看 sendServiceArgsLocked 是如何實現的。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();
    if (N == 0) {
        return;
    }

    while (r.pendingStarts.size() > 0) {
        Exception caughtException = null;
        ServiceRecord.StartItem si;
        try {
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } catch (TransactionTooLargeException e) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
                    + si.intent);
            caughtException = e;
        } catch (RemoteException e) {
            // Remote process gone...  we'll let the normal cleanup take care of this.
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
            caughtException = e;
        } catch (Exception e) {
            Slog.w(TAG, "Unexpected exception", e);
            caughtException = e;
        }

        if (caughtException != null) {
            // Keep nesting count correct
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            if (caughtException instanceof TransactionTooLargeException) {
                throw (TransactionTooLargeException)caughtException;
            }
            break;
        }
    }
}

這里通過循環的方式,將在隊列中的消息,依次通過 app.thread 發布到應用進程中去,如果中途發生了 TransactionTooLargeException 異常,則會提前終止這個過程。 app.thread 的 scheduleServiceArgs 方法,也是通過 mH 這個 Handler 來執行的,發送的消息為 SERVICE_ARGS 。

case SERVICE_ARGS:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
    handleServiceArgs((ServiceArgsData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
private void handleServiceArgs(ServiceArgsData data) {
    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) {
                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, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                // nothing to do.
            }
            ensureJitEnabled();
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

handleServiceArgs 方法中, s.onStartCommand 就是我們書寫后臺代碼的地方,當這個方法執行完成后,又通過 gDefault 這個遙控器通知 AMS 來任務完成了。

對于 startService 這種方式而言,是需要手動調用 stopSelf 方法來結束 Service 的,背后的原理與 startService 方法類似,這里就不再贅述。

0X02 bindService 調用流程

bindService 相較于 startService 要復雜一些,通過這種方式實現的 Service,容易多個組件綁定到它,通過 ServiceConnection 的方式來進行通信。當沒有任何其他組件,連接到這個 Service 時,該 Service 會自動銷毀。

bindService 方法是這樣聲明的。

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        UserHandle user) {
    // ignore some codes ...
    validateServiceIntent(service);
    try {
        // ignore some codes ...
        int res = ActivityManagerNative.getDefault().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
        if (res < 0) {
            throw new SecurityException(
                    "Not allowed to bind to service " + service);
        }
        return res != 0;
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

可以看到同樣是通過 gDefault 這個遙控器來通知 AMS 進行相應的操作的,原理與上面 startService 相同,接收到遙控器的指令后,ActiveServices 的 bindSericeLocked 方法開始執行。bindSericeLocked 在進行一些校驗,確認進程創建成功等等步驟后,還是通過 app.thread 發送 BIND_SERVICE 消息,來執行對應的邏輯。

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) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to bind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

在 onBind 方法,給調用者返回 Binder 對象,通過 publishService 方法通過到 AMS 內部去,我們看看接下來發生了什么。

public void publishService(IBinder token, Intent intent, IBinder service) {
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    synchronized(this) {
        if (!(token instanceof ServiceRecord)) {
            throw new IllegalArgumentException("Invalid service token");
        }
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
}

ActiveServices 中的代碼也相對簡單, 遍歷建立起的 ServiceConnection,并調用它們的 connected 方法,這也是我們需要編寫后臺代碼的地方。

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                + " " + intent + ": " + service);
        if (r != null) {
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);
            if (b != null && !b.received) {
                b.binder = service;
                b.requested = true;
                b.received = true;
                for (int conni=r.connections.size()-1; conni>=0; conni--) {
                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                    for (int i=0; i<clist.size(); i++) {
                        ConnectionRecord c = clist.get(i);
                        if (!filter.equals(c.binding.intent.intent)) {
                            continue;
                        }
                        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                        try {
                            c.conn.connected(r.name, service);
                        } catch (Exception e) {
                            Slog.w(TAG, "Failure sending service " + r.name +
                                  " to connection " + c.conn.asBinder() +
                                  " (in " + c.binding.client.processName + ")", e);
                        }
                    }
                }
            }

            serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

0X03 總結

Service 作為四大組件之一,提供了不需要前臺頁面情況下,在后臺繼續執行任務的能力。Service 一般有兩種使用方式,分別是通過 startService 和 bindService,前者適合執行一次性的任務,而后者則具備一定交互的能力,可以用作處理相對復雜的后臺邏輯。

 

 

 

來自:http://www.jianshu.com/p/e85c63be4266

 

 本文由用戶 dsgfjuyjd 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!