原文鏈接:http://www.woaitqs.cc/2016/09/20/android-service-usage.html
本文是 Android 系統(tǒng)學(xué)習(xí)系列文章中的第三章節(jié)的內(nèi)容烹卒,介紹了 Android Service 相關(guān)的基礎(chǔ)知識,然后從源碼的角度上分析 Service 的一些實現(xiàn)原理踩叭。對此系列感興趣的同學(xué)拳缠,可以收藏這個鏈接 Android 系統(tǒng)學(xué)習(xí)渔彰,也可以點擊 RSS訂閱 進行訂閱
0X00 Service 基礎(chǔ)知識
Service 作為 Android 提供的四大組件之一欧芽,主要負責(zé)一些沒有前臺顯示的后臺任務(wù)症脂。即使應(yīng)用本身不再可見织鲸,Service 的屬性也能使得其在后臺運行句占。除此之外沪摄,Service 也可以通過 Binder 機制,與界面甚至其他應(yīng)用進行進程間通信纱烘,以實現(xiàn)相應(yīng)的交互杨拐。這里需要簡單說明的是,既然是后臺任務(wù)擂啥,為什么不選用 Thread 了哄陶?選用 Service 和 Thread 的主要區(qū)別在于需不需要在應(yīng)用不可見的時候依然保留。舉例來說哺壶,新聞詳情頁面的數(shù)據(jù)請求屋吨,只用在當前頁面生效,而音樂播放這些后臺任務(wù)就可以通過 Service 的方式來實現(xiàn)山宾。
關(guān)于如何使用 Service离赫,官方教程已經(jīng)說明得足夠詳細了,如果對這些用法塌碌,還有不清晰的地方渊胸,請戳這里進行查看,-> 官方教程台妆。官方教程里面包括翎猛,startService 和 bindService 的區(qū)別,在不同場景下應(yīng)該選用哪種 Service 實現(xiàn)方式接剩。
0X01 startService 調(diào)用流程
從前面的教程里面切厘,可以知道 Service 的啟動一般有兩種方式,分別是 bindService 和 startService懊缺。這里主要說明 startService疫稿, 具體的實現(xiàn)邏輯在 ContextImpl 中,我們看看源碼是怎么實現(xiàn)的鹃两。
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
接下來遗座,看看方法內(nèi)部具體是怎么實現(xiàn)的。
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 來執(zhí)行的途蒋。如果看過我的另一篇文章,Android Activity 生命周期是如何實現(xiàn)的, 可能會覺得很熟悉馋记。事實上這里采用的機制就是同樣的号坡。
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 方法是這么實現(xiàn)的懊烤。可以看到宽堆,gDefault 是類型為 IActivityManager 的 Binder 對象腌紧。而這個 Binder 對象可以看做是在 System Server 中的 ActivityManagerService 的句柄,通過這個 Binder 對象畜隶,可以跨進程調(diào)用 ActivityManagerService寄啼。
如果上述內(nèi)容不容易理解的話,我們可以類比地來看這個問題代箭。我們遙控電視的時候墩划,例如進行增加音量的操作,這個操作實際不是由遙控器完成的嗡综,而是電視中的電子元件完成的乙帮。遙控器會和電視進行協(xié)商,先聲明有哪些操作可以執(zhí)行极景,然后將這些協(xié)商后的操作在遙控器端和電視端 ?? 都實現(xiàn)察净,區(qū)別在于電視機是真的實現(xiàn),而遙控器只是發(fā)送操作指令而已盼樟。前面代碼中提及的 gDefault 就是 ActivityManagerService 的遙控器氢卡。
[圖片上傳失敗...(image-9ead3a-1512375661501)]
接著往下看看電視端是具體怎么操作的,這里的電視端就是 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 相關(guān)的邏輯都在這里面击碗。
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());
// 調(diào)用進程的優(yōu)先級是否足夠
final boolean callerFg;
if (caller != null) {
// 能否找到相應(yīng)的 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) {
// 避免同時有多個服務(wù)啟動時筑悴,造成的性能問題,如果超過閾值后稍途,就進行延遲
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 主要進行了權(quán)限校驗和為性能進行的調(diào)度阁吝,具體的邏輯,還在 startServiceInnerLocked 方法里面械拍。
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ProcessStats.ServiceState stracker = r.getTracker();
if (stracker != null) {
// 跟蹤 Service 內(nèi)存試用狀況
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);
}
// 設(shè)置超時時間
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 是如何實現(xiàn)的突勇,這里就是實際啟動 Service 的地方。
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
// 目標Service已經(jīng)啟動
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)) {
// 重試計數(shù)
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 標記起來后,
// 可以避免在這個過程中又創(chuàng)建了一個進程
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);
// 如果應(yīng)用進程已經(jīng)創(chuàng)建海蔽,而且 Looper 線程已經(jīng)準備完畢
// 那么就調(diào)用 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;
}
// 應(yīng)用進程還未創(chuàng)建共屈,這里需要先啟動應(yīng)用進程
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;
}
上面的代碼較為復(fù)雜,這里進行下初步的總結(jié)党窜。首先判斷服務(wù)是否已經(jīng)啟動拗引,或者正在重啟中,則直接返回幌衣。其后矾削,當前 Service 進程正在啟動中,也直接返回豁护。最后判斷應(yīng)用進程是否啟動哼凯,如果沒有啟動進程,則先啟動進程楚里。
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 對象,通過創(chuàng)建目標 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 來執(zhí)行的班缎,這里就會通知客戶端.
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));
}
// 通知調(diào)用 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 不同之處在于兩者的方向是相反的。前者是應(yīng)用進程操作AMS达址,而后者則是AMS操作應(yīng)用進程蔑祟。IApplicationThread 對應(yīng)的實現(xiàn)是 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 這種方式來執(zhí)行的呀疆虚,這與前面文章提及的知識是完全一樣的。如果大家想詳細地了解的話满葛,建議看看這些系列文章 Android 系統(tǒng)學(xué)習(xí)計劃装蓬。在 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;
繼續(xù)看 handleCreateService 方法的實現(xiàn)纱扭。
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);
}
}
}
方法實現(xiàn)相對簡單牍帚,首先通過 ClassLoader 加載相關(guān)的 class 對象,然后將 Service 和 Application 綁定在一起乳蛾,最后調(diào)用 Service 的 onCreate 方法暗赶。到此為止,Service 就完全啟動了肃叶。
如果使用 Service 的方式是 startService蹂随,那么在 Service 啟動后,就可以執(zhí)行 sendServiceArgsLocked 方法因惭,從而在 Service 的 onStartCommand 里面可以執(zhí)行相應(yīng)的后臺代碼岳锁,需要特別說明的是,這個是執(zhí)行在 UI 線程上的,因而建議不要執(zhí)行耗時的任務(wù)等脂,如果是耗時的任務(wù),需要通過多線程的方式來避免主線程的阻塞茫船。即使應(yīng)用當前不在前臺乒躺,阻塞 UI 線程招盲,也是很不好的情況。
我們看看 sendServiceArgsLocked 是如何實現(xiàn)的嘉冒。
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;
}
}
}
這里通過循環(huán)的方式曹货,將在隊列中的消息,依次通過 app.thread
發(fā)布到應(yīng)用進程中去讳推,如果中途發(fā)生了 TransactionTooLargeException 異常顶籽,則會提前終止這個過程。app.thread
的 scheduleServiceArgs 方法银觅,也是通過 mH 這個 Handler 來執(zhí)行的礼饱,發(fā)送的消息為 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
就是我們書寫后臺代碼的地方慨仿,當這個方法執(zhí)行完成后,又通過 gDefault 這個遙控器通知 AMS 來任務(wù)完成了纳胧。
對于 startService 這種方式而言镰吆,是需要手動調(diào)用 stopSelf 方法來結(jié)束 Service 的,背后的原理與 startService 方法類似跑慕,這里就不再贅述万皿。
0X01 bindService 調(diào)用流程
bindService 相較于 startService 要復(fù)雜一些,通過這種方式實現(xiàn)的 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 進行相應(yīng)的操作的位岔,原理與上面 startService 相同,接收到遙控器的指令后堡牡,ActiveServices 的 bindSericeLocked 方法開始執(zhí)行抒抬。bindSericeLocked 在進行一些校驗,確認進程創(chuàng)建成功等等步驟后晤柄,還是通過 app.thread
發(fā)送 BIND_SERVICE
消息擦剑,來執(zhí)行對應(yīng)的邏輯。
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 方法,給調(diào)用者返回 Binder 對象惠勒,通過 publishService 方法通過到 AMS 內(nèi)部去赚抡,我們看看接下來發(fā)生了什么。
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捉撮,并調(diào)用它們的 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);
}
}
0X02 總結(jié)
Service 作為四大組件之一巾遭,提供了不需要前臺頁面情況下,在后臺繼續(xù)執(zhí)行任務(wù)的能力闯估。Service 一般有兩種使用方式灼舍,分別是通過 startService 和 bindService,前者適合執(zhí)行一次性的任務(wù)涨薪,而后者則具備一定交互的能力骑素,可以用作處理相對復(fù)雜的后臺邏輯。
關(guān)于更多詳細的用法刚夺,還是建議閱讀官方教程献丑,Services.
文檔信息
- 版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證)
- 發(fā)表日期:2016年9月20日
- 社交媒體:weibo.com/woaitqs
- Feed訂閱:www.woaitqs.cc/feed.xml