3,服务所在进程
服务所在进程调用流程图如下,
3.1服务已启动
服务已启动,则直接调用sendServiceArgsLocked方法,
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
while (r.pendingStarts.size() > 0) {
Exception caughtException = null;
ServiceRecord.StartItem si;
try {
si = r.pendingStarts.remove(0);
•••
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
•••
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (TransactionTooLargeException e) {
caughtException = e;
} catch (RemoteException e) {
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;
}
}
}
这里也涉及到跨进程通信,由AMS所在进程转移到要启动的服务所在进程A。仔细研究ApplicationThreadNative.java源码,
r.app.thread指ApplicationThreadProxy对象,利用Binder机制,转移到进程A主线程(ActivityThread)当中继续执行.
ApplicationThreadNative类和ApplicationThreadProxy类实现了IApplicationThread接口,而ApplicationThreadNative类,
所以ApplicationThreadNative类分别运行于AMS进程以及服务所在进程,这种设计在framework源码中很常见。
scheduleServiceArgs方法如下,
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
scheduleServiceArgs只是向该主线程发送了一个消息,
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();
•••
} catch (Exception e) {
•••
}
}
}
跨进程的调用一般首先向主线程发送消息,切换到主线程中执行。
终于看到调用服务的onStartCommand方法了, 由于方法运行于主线程中,所以不要在onCreate()、onStart()里执行耗时的操作。
3.2 启动服务
启动服务会调用realStartServiceLocked方法,和上一小节的过程完全一样,也是跨进程通信,发送消息,最后调用利用发射机制构造
服务对象,调用服务的onCreate方法.
private void handleCreateService(CreateServiceData data) {
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) {
•••
}
try {
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) {
•••
}
}
在realStartServiceLocked方法中首先利用反射构造service对象,然后调用sendServiceArgsLocked方法。
sendServiceArgsLocked方法见上个小节。
3.3 启动apk,然后启动服务
服务所在的apk未启动,则调用AMS的startProcessLocked方法,apk详细的启动流程就不论述了,完成apk的启动之后,
在attachApplicationLocked方法中,会依次启动四大组件中的activity,service和broadcast。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
•••
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) { // 启动activity
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
// 启动service
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
didSomething |= sendPendingBroadcastsLocked(app); // 启动
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
}
再看attachApplicationLocked方法,依然会调用realStartServiceLocked方法完成最后的服务启动。
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
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)) {
•••
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
•••
}
}
•••
}
因此,如果服务所在的apk未启动,会首先启动apk,然后启动服务。
其实,service的流程和activity流程几乎相同,跨进程调用完全相同。
这里涉及到2个跨进程通信:
1,从apk到AMS。ActivityManagerProxy是AMS的在客户端的代理。
2,从AMS到apk。ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。
AMS就是通过该代理与ActivityThread进行通信的。ApplicationThread是ActivityThread的内部类。