前面分析了應用内部Activity的啟動過程,其實如果是應用第一個Activity的啟動,流程上還會多一些建立程序和ActivityThread的過程。Service同樣也是如此,如果是應用内部啟動服務,且沒有配置android:process的話,預設就在應用程序中啟動,下面我們就配置android:process=“:remote”,讓服務在另一個程序中啟動。
private void startServiceTest(){
Intent intent = new Intent("com.android.wuliq.service");
startService(intent);
}
接着進入ContextImpl.java
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
@Override
public boolean stopService(Intent service) {
warnIfCallingFromSystemProcess();
return stopServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到跟Activity啟動很類似,調用ActivityManagerNative.getDefault().startService進行跨程序通訊。getDefault()擷取本地代理ActivityManagerProxy對象,調用ActivityManagerProxy中的startService方法:
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
用遠端binder對象mRemote調用transact會通過底層binder驅動轉到遠端服務的中間者stub(ActivityManagerNative):
case START_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
String callingPackage = data.readString();
int userId = data.readInt();
ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
}
可以看到遠端這邊通過IApplicationThread app = ApplicationThreadNative.asInterface(b);擷取本地代理ApplicationThreadProxy,後面從服務端調用用戶端接口需要用到它。
接着調用到服務端實作者AMS:
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
}
這裡調用了ActiveServices.java中的startServiceLocked方法:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
ServiceRecord r = res.record;
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
這裡會通過retrieveServiceLocked去檢索AndroidManifest.xml檔案并将服務資訊存儲在ServiceRecord中。接着跳轉到startServiceInnerLocked,裡面又跳轉到bringUpServiceLocked函數:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
ProcessRecord app;
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
realStartServiceLocked(r, app, execInFg);
}
if (app == null && !permissionsReviewRequired) {
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;
}
}
}
這裡的mAm為ActivityManagerService類型,如果擷取程序資訊不為空,則調用realStartServiceLocked啟動服務。這裡我們要求在另一個程序中啟動,是以程序并未建立,為空。是以調用AMS的startProcessLocked方法,開啟程序:
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
this.mPidsSelfLocked.put(startResult.pid, app);
}
這裡調用Process.start函數建立了一個新的程序,指定新的程序執行android.app.ActivityThread類。最後将表示這個新程序的ProcessRecord儲存在mPidSelfLocked清單中。
建立一個程序後,然後導入android.app.ActivityThread這個類,然後執行它的main函數:
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
可以看到這裡建立了ActivityThread對象,并建立looper和消息隊列。主線程的消息隊列就是在這裡建立的。在Android應用程式中,每一個程序對應一個ActivityThread執行個體,這裡調用ActivityThread.attach函數進一步處理:
private void attach(boolean system) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
可以看到,又是跨程序通路,由經驗得知,直接進入AMS的attachApplication函數:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
app = mPidsSelfLocked.get(pid);
mServices.attachApplicationLocked(app, processName);
}
擷取之前儲存的程序資訊,接着調用ActiveServices.java的attachApplicationLocked函數:
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
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);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeeded(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);
}
}
}
擷取之前儲存的服務資訊,調用realStartServiceLocked啟動服務:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
sendServiceArgsLocked(r, execInFg, true);
}
這裡的app.thread就是前面attachApplication的時候擷取的用戶端的本地代理ApplicationThreadProxy,調用它的scheduleCreateService會跨程序到用戶端的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);
}
下面的流程就跟Activity的啟動很相似了。
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
private void handleCreateService(CreateServiceData data) {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
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();
}
可以看到這裡擷取ClassLoader建立了Service,并建立了ContextImpl、Application等,attach給service,最後調用onCreate()。
至于onStartCommand是在什麼時候調用呢,跟蹤代碼發現在ActiveServices.java中app.thread.scheduleCreateService執行完後,調用了sendServiceArgsLocked(r, execInFg, true);函數,也是跨程序到用戶端,發消息調用onStart。
至此,這個自定義的服務就啟動起來了。
這樣,Android系統在新程序中啟動服務的過程就分析完成了,雖然很複雜,但是條理很清晰。它通過三次Binder程序間通信完成了服務的啟動過程,分别是:
一. 從主程序調用到ActivityManagerService程序中,完成新程序的建立;
二. 從新程序調用到ActivityManagerService程序中,擷取要在新程序啟動的服務的相關資訊;
三. 從ActivityManagerService程序又回到新程序中,最終将服務啟動起來。