Android 11源碼分析:Service工作流程

ZhaoYun 2021-08-15 13:37:13 阅读数:786

本文一共[544]字,预计阅读时长:1分钟~
android 分析 service 工作流 工作

我們知道Service分為兩種工作狀態,一種是啟動狀態,一種是綁定狀態。前者適用於後臺計算,後者適用於Service與其他組件的交互。 我們知道Service有兩種生命周期

  • startService啟動方式:onCreate()--->onStartCommand() --->onDestroy();

  • bindService啟動方式:onCreate()--->onBind() --->onUnbind()--->onDestroy();

Service的啟動過程

從Activity的startServic開始旅程。點擊會進入ContextWrapper類的startService方法

android.content.ContextWrapper
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
複制代碼

mBase是ContextImpl類型,在Activity啟動過程中,執行attach方法時進行關聯。具體代碼在文字末尾附加

ContextWrapper的大部分操作都是通過mBase實現。這就是橋接模式 下面去看看具體實現

android.appContextImpl
class ContextImpl extends Context {
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
......
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
}
}
複制代碼

ActivityManager.getService()獲取的就是ActivityManageService,一般簡稱AMS,源碼中出現很頻繁,還不清楚的可以去看看我之前的文章。

繼續去看AMS下的startService

com.android.server.am.ActivityManagerService
final ActiveServices mServices;
......
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
......
ComponentName res;
try {
關鍵代碼
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
複制代碼

如果是打開AS跟著看代碼的小夥伴,可以滾動鼠標看看上下的方法,其實都是和Service相關的,所以記住AMS這個類吧。

mServices是ActiveServices類型的,後續的Service操作由它完成。

com.android.server.am.ActiveServices
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
......
關鍵代碼
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs =
shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
callingUid, service, r, allowBackgroundActivityStarts);
}
return cmp;
}
複制代碼

在startServiceLocked中調用startServiceInnerLocked

com.android.server.am.ActiveServices
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;
......
關鍵代碼
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
......
return r.name;
}
複制代碼

bringUpServiceLocked方法內部挺長的,看的迷迷糊糊,忽然看的一個realStartServiceLocked方法。看這名字,應該就是真正啟動Service的地方了吧。

com.android.server.am.ActiveServices
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
......
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
......
sendServiceArgsLocked(r, execInFg, true);
......
}
複制代碼

app.thread 和ActivityManager.getService()一樣,也是很常見的引用,就是ApplicationThread對象

Service的onCreate

接下來去ApplicationThread看看scheduleCreateService做了些什麼,看過文章的小夥伴,就該知道,多半又是去發消息了。

android.app.ActivityThread
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);
}
在內部類H中,對這個消息的處理是
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
複制代碼

熟悉的套路,去ApplicationThread發消息,H去處理具體實現。

android.app.ActivityThread
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
創建ContextImpl對象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
獲取application
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
通過反射獲取service
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
將ContextImpl於Service建立鏈接,與Activity類似
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
執行Service的onCreate
service.onCreate();
將當前Service添加到mServices中
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. 創建ContextImpl對象
  2. 創建Application,當然這個東西全局只有一個,在Appliction初始化中介紹過
  3. 通過反射獲取service
  4. 將ContextImpl於Service建立鏈接
  5. 執行Service的onCreate
  6. 將當前Service添加到mServices中,定義如下

至此,Service的onCreat 執行了,也就意味著Service啟動了。

final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
複制代碼

Service的onStartCommond

在前面的代碼realStartServiceLocked方法內部,下面還有一個關鍵方法sendServiceArgsLocked

com.android.server.am.ActiveServices
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
......
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
......
}
......
}
複制代碼

執行了ApplicationThread的scheduleServiceArgs方法

android.app.ActivityThread
內部類ApplicationThread中:
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
......
sendMessage(H.SERVICE_ARGS, s);
}
}
內部類H中:
case SERVICE_ARGS:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceStart: " + String.valueOf(msg.obj)));
}
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
private void handleServiceArgs(ServiceArgsData data) {
// 從mServices取出Service實例
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) {
執行onStartCommand
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
......
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
複制代碼

在handleServiceArgs中, 先是從mServices中取出之前創建好的Service,然後執行Service的onStartCommand方法。這也就說明了,onStartCommand確實是在onCreate之後執行的。

Service的綁定過程

與Service的啟動過程一樣,bindService在ContextImpl中實現,內部會調用bindServiceCommon

android.content.ContextWrapper
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
複制代碼

內部調用的是bindServiceCommon方法,需要我們重點關注一下

android.content.ContextImpl
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
......
①將conn參數傳入getServiceDispatcher,獲取IServiceConnection類型的對象 sd
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
②通過AMS完成綁定操作
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
複制代碼

bindServiceCommon方法比較長,主要做了兩件事:

  1. 將ServiceConnection對象conn轉換成ServiceDispatcher.InnerConnection類型對象sd
  2. 通過AMS完成綁定操作

我知道只看上面代碼得出做了上述的兩件事的結論是比較懵逼的,無妨,我們進到具體代碼來說明。

將ServiceConnection類型轉換成ServiceDispatcher.InnerConnection

首先,來確定為什麼說IServiceConnection的實例sd實際上是ServiceDispatcher.InnerConnection類型。

sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags); 點擊getServiceDispatcher可以發現在類LoadedApk中,這個類我們也不陌生,因為Application的創建就在這個類裏。

android.app.LoadedApk
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
return getServiceDispatcherCommon(c, context, handler, null, flags);
}
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
......
return sd.getIServiceConnection();
}
}
複制代碼

這邊最後進入的是ServiceDispatcher類裏的getIServiceConnection方法

android.app.LoadedApk
static final class ServiceDispatcher{
private final ServiceDispatcher.InnerConnection mIServiceConnection;
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
}
複制代碼

問題得到解釋,getIServiceConnection方法最後返回的mIServiceConnection是ServiceDispatcher.InnerConnection類型。 新的問題又來了,為什麼要這麼大費周章的去將ServiceConnection轉換成ServiceDispatcher.InnerConnection呢? 《Android開發藝術探索》是這麼解釋的:

之所以不能直接使用ServiceConnection對象,這是因為服務的綁定可能是跨進程的,因此ServiceConnection對象必須借助於Binder才能讓遠程服務端回調自己的方法,而ServiceDispatcher的內部類InnerConnection剛好充當Binder這個角色,那麼ServiceDispatcher的作用起著鏈接ServiceConnection和InnerConnection的作用。

ActivityManagerSerice完成綁定

我們已經熟悉的指導ActivityManager.getService()其實獲取的就是ActivityManagerSerice(AMS)對象,所以去裏面找bindIsolatedService即可

com.android.server.am.ActivityManagerSerice
final ActiveServices mServices;
......
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
......
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
複制代碼

流程來到ActiveServices中

com.android.server.am.ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
內部執行onCreate
bringUpServiceLocked(serviceRecord,serviceIntent.getFlags(),callerFg, false, false);
......
內部執行onBind
requestServiceBindingLocked(s, b.intent, callerFg, true);
......
}
複制代碼

這裏的流程和Serice啟動的流程其實類似,第一步都是創建Service,然後執行啟動或者綁定方法。bringUpServiceLocked內部就是執行Service的OnCreate,requestServiceBindingLocked內部則是執行綁定。

com.android.server.am.ActiveServices
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
......
realStartServiceLocked(r, app, execInFg);
......
}
複制代碼

可以看到在bringUpServiceLocked內部,同樣執行了realStartServiceLocked 方法,這個方法在分析Service啟動流程中已經看到過,就是執行Service的onCreate。接著看

com.android.server.am.ActiveServices
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
......
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
......
}
複制代碼

同樣的套路,去ApplicationThread發個消息,去H中執行。

android.app.ActivityThread
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
......
sendMessage(H.BIND_SERVICE, s);
}
在內部類H中,對這個消息的處理是
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
複制代碼

看看handleBindService具體做了啥吧

android.app.ActivityThread
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();
//這裏的代碼就是說明,為什麼我們常說Service只能綁定一次了
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
系統告知客戶端已經成功鏈接Service了
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} 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);
}
}
}
}
複制代碼

handleBindService做了兩件事,

  1. 執行onBind
  2. 通知客戶端已經完成了Service的綁定

當我自己分析到這的時候,我以為已經結束了。後面在《Android開發藝術》看到:onBind是Service的方法,客戶端自己並不知道已經鏈接成功了,所以才有後面的通過AMS去通知客戶端的操作。

所以繼續分析唄:如何通知客服端,服務已經綁定成功。直接去AMS找

com.android.server.am.ActivityManagerService
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是ActiveServices類型
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
複制代碼
com.android.server.am.ActiveServices
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
......
c.conn.connected(r.name, service, false);
} catch (Exception e) {
}
}
複制代碼

這個conn是之前提過的ServiceDispatcher.InnerConnection類型

android.app.LoadedApk
static final class ServiceDispatcher {
private final ServiceConnection mConnection;
......
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
關鍵代碼
doConnected(name, service, dead);
}
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
......
mActivityThread.post(new RunConnection(name, service, 0, dead));
}
}
複制代碼

mActivityThread內部有個Handler類型的H,所以這個方法直接post到主線程執行。RunConnection定義如下

 private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
//關鍵代碼
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
複制代碼
public void doConnected(ComponentName name, IBinder service, boolean dead) {
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
複制代碼

mConnection就是我們一使用bindService傳入的第二個參數,至此客戶端的onServiceConnected執行,Service的綁定過程分析完成。

如果你對mConnection.onServiceConnected(name, service);這個行代碼為何代錶客戶端已經執行onServiceConnected的結論還有疑問,文章末尾會加以解析

附加:mBase是個啥

android.content.ContextWrapper
mBase的賦值
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
android.app.Activity
@UnsupportedAppUsage
final void attach(Context context, ...) {
attachBaseContext(context);
......
}
而我們知道attach方法是在ActivityThread的performLaunchActivity內調用
android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
......
所以mBase就是ContextImpl類型
activity.attach(appContext,...);
......
}
複制代碼
版权声明:本文为[ZhaoYun]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815133652354C.html