この記事の内容は、ほとんどが「AndroidAdvancedDecryption」という本からのものです。ですから、あまりお役に立てないかもしれませんが、この記事を書く目的は、もう一度勉強したときに印象を与え、自分に便利さを提供することです。
サービスの起動プロセスは、ContextImplからActivityManagerServiceへの呼び出しプロセスと、ActivityThreadがサービスを開始するプロセスの2つの部分に分かれています。
1.ContextImplからActivityManagerServiceへの呼び出しプロセス
アクティビティでサービスを開始するとき、最初にContextWrapperクラスに実装されているstartServiceメソッドを呼び出します。メソッド本体には、次の1行のコードしかありません。
@Override public ComponentName startService(Intent service){ return mBase.startService(service); }
次に、ContextタイプのmBaseオブジェクトが何を参照しているかを見てみましょう。ActivityThreadがActivityを開始するプロセスで、createBaseContextForActivityメソッドがActivityThreadのperformLaunchActivityメソッドで呼び出され、ContextImplタイプのコンテキストオブジェクトが作成されます。次に、作成したコンテキストオブジェクトAppContextをapp.attachメソッドに渡します。createBaseContextForActivityメソッドで何が行われるかを見てみましょう。コードは次のように表示されます。
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
// 代码省略。。。
// 调用createActivityContext创建上下文对象
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
// 代码省略。。。
return appContext;
}
activity.attachメソッドに渡されるappContextオブジェクトのタイプがContextImplであることがわかります。Activityクラスのattachメソッドでは、ContextWrapperクラスのattachBaseContextメソッドが呼び出されます。メソッドコードは次のとおりです。
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
// 将传递进来的ContextImpl(继承自Context)类型的base对象赋值给了mBase变量
mBase = base;
}
したがって、mBaseは特にContextImplを参照します。したがって、サービスを開始するプロセスは、ContextImplクラスから始まります。コードは次のように表示されます。
@Override public ComponentName startService(Intent service){ warnIfCallingFromSystemProcess(); //调用了startServiceCommon方法 returnstartServiceCommon(service、false、mUser); }
コードから、startServiceCommonメソッドがContextImpl.startServiceメソッドで返されることがわかります。それでは、このメソッドで何が行われるかを見てみましょう。
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
// 代码省略。。。
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
おなじみのActivityManager.getService()。startService(....);コードがこのメソッドに表示されます。Activity起動プロセスに精通している人は、このコードが実際にActivityManagerServiceのstartServiceメソッドを呼び出すことを知っている必要があります。この時点で、ContextImplからAMSへの呼び出しプロセスは終了しています。シーケンス図は次のとおりです。
次に、ActivityThreadがサービスを開始するプロセス
前のプロセスの後、AMSのstartServiceメソッドに対してコードロジックが実行されます。このメソッドは、ActiveServicesのstartServiceLockedメソッドを呼び出します。コードは次のとおりです。
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
// 代码省略。。。
// 注释1:查找是否有与参数service对应的ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
// 注释2:得到参数service对应的ServiceRecord
ServiceRecord r = res.record;
// 代码省略。。。。
// 注释3
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
注1、retrieveServiceLockedメソッドが呼び出されます。その役割は、パラメーターserviceに対応するServiceRecordがあるかどうかを確認することです。コードの実装は次のとおりです。
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
if (r == null) {
try {
// 注释1:
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId, callingUid);
// 注释2
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
}
if (r != null) {
// 代码省略。。。
// 注释3
return new ServiceLookupResult(r, null);
}
return null;
}
注1は、最終的にPackageManagerServiceを呼び出して、パラメーターserviceに対応するサービス情報を取得します。注2では、最初のステップで取得したパラメータserviceに対応するサービス情報をServiceRecordにカプセル化します。注3、ServiceRecordをServiceLookupResultオブジェクトの形式でActiveServicesのstartServiceLockedメソッドに返します。startServiceLockedメソッドのコメント2では、パラメーターserviceに対応するServiceRecordは、コメント1で返されたServiceLookupResultを介して取得され、コメント3でstartServiceInnerLockedメソッドに渡されます。このメソッドのコードは主にbringUpServiceLockedメソッドを呼び出しますが、ここでは示しません。bringUpServiceLockedメソッドのコードを直接見てください。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 代码省略。。。
// 注释1
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
// 注释2
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
// 注释3
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 注释4
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 {
// 。。。。
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
// 注释5
if (app == null && !permissionsReviewRequired) {
// 注释6
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;
}
}
// 。。。。
return null;
}
注1、ServiceRecordのprocessName値を取得し、それをprocNameに割り当てます。ここで、processNameは、サービスを実行するプロセスを記述するために使用され、デフォルトは現在のプロセスです。注2:サービスのprocNameとuidをAMSのgetProcessRecordLockedメソッドに渡して、サービスに対応するProcessRecordタイプのオブジェクトアプリがあるかどうかを照会します。ProcessRecordは主に、実行中のアプリケーションプロセスの情報を記述するために使用されます。注3の判断は、サービスの実行に使用されたアプリケーションプロセスが存在することを示しており、この時点で注4のrealStartServiceLockedメソッドが呼び出されます。注5の判断は、サービスに対応する申請プロセスがまだ作成されていないことを示しており、この時点で注6のコードが呼び出されます。注6は、AMSのstartProcessLockedメソッドを呼び出して、サービスに対応するアプリケーションプロセスを作成します。次に、注4のrealStartServiceLockedメソッドを見てみましょう。コードは次のとおりです。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// 注释1
if (app.thread == null) {
throw new RemoteException();
}
try {
// 注释2
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 {
// 代码省略。。。
}
// 代码省略。。。
}
このメソッドには多くのコードが含まれていますが、確認する必要があるのは2つだけです。注1、この時点で、サービスに対応するアプリケーションプロセスが作成されていない場合、例外がスローされることに注意する必要があります。注2、app.threadのscheduleCreateServiceメソッドを呼び出します。また、app.threadのタイプはIApplicationThreadであり、その実装はActivityThreadの内部クラスApplicationThreadです。メソッドコードは次のとおりです。
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);
}
このメソッドは、サービスの開始に必要な情報をCreateServiceDataにカプセル化し、sendMessageメソッドを介してCREATE_SERVICEメッセージをクラスHに送信します。クラスHのhandleMessageメソッドでのCREATE_SERVICEの処理を直接確認します。
private class H extends Handler {
// 代码省略。。。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
// 省略代码。。。
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
// 调用了handleCreateService方法
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
CREATE_SERVICEの処理は、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();
// 注释1
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 注释2
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
//.....
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
// 注释3
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 注释4
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 注释5
service.onCreate();
// 注释6
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) {
// 。。。
}
}
このメソッドは、上記のいくつかを実行します。注1:開始するサービスのアプリケーションのLoadedApkを取得します。注2、クラスローダーを取得し、クラスローダーに基づいてサービスインスタンスを作成します。注3、サービスコンテキストのContextImplオブジェクトを作成します。注4、サービスのattachメソッドを呼び出してサービスを初期化し、前の手順で作成したContextImplオブジェクトコンテキストを渡します。このサービスメソッドでは、ContextWrapperのattachBaseContextメソッドが呼び出され、パラメータコンテキストがmBaseに割り当てられます。注5は、サービスのonCreateライフサイクルメソッドを呼び出して、サービスを開始します。注6、開始されたサービスをActivityThreadのメンバー変数mServicesに追加します。ここで、mServicesは、キーとしてIBinderを、値としてServiceを使用するArrayMapコレクションです。
この時点で、サービスの起動プロセスは終了し、最後にこのプロセスのシーケンス図を添付してこの記事を終了します。
この時点で記事は終わりました。本「AndroidAdvancedDecryption」の著者に感謝します。