其实启动Service和我们上一篇启动App的流程差不多,通过学习老罗的Android系统在新进程中启动自定义服务过程(startService)的原理分析,补充了一些不太清楚的知识点。这里做一下笔记。
老罗的例子,Service是设置了一个android:process属性,表明要在新建的进程运行Service。例子xml代码:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="shy.luo.ashmem"
android:sharedUserId="android.uid.system"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
......
<service
android:enabled="true"
android:name=".Server"
android:process=".Server" ><!-- 设置了process属性 -->
<intent-filter>
<action android:name="shy.luo.ashmem.server"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
</manifest>
在这篇博文中,讲述了ActivityManagerService是在一个ServerThread类(有种熟悉的感觉,ActivityThread,不过没有联系的,哈哈)中启动的,代码如下:
class ServerThread extends Thread {
......
@Override
public void run() {
......
// Critical services...
try {
......
context = ActivityManagerService.main(factoryTest);
......
ActivityManagerService.setSystemProcess();
......
} catch (RuntimeException e) {
Slog.e("System", "Failure starting core service", e);
}
......
}
......
}
调用了ActivityManagerService的main和setSystemProcess方法,我们接着看代码:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
static ActivityManagerService mSelf;
......
public static void setSystemProcess() {
try {
ActivityManagerService m = mSelf;
ServiceManager.addService("activity", m);
......
} catch (PackageManager.NameNotFoundException e) {
......
}
}
......
public static final Context main(int factoryTest) {
......
ActivityManagerService m = thr.mService;
mSelf = m;
......
}
}
在setSystemProcess方法里,调用了ServiceManager的addService方法,这样ActivityManagerService作为Service注册到ServiceManager中,Client就可以在ServiceManager中获取到ActivityManagerService的代理对象,并与之通信。这样ActivityManagerService就算是“启动”起来了。
当我们通过startService启动Service时,和启动App一样,其实是调用ActivityManagerService代理对象ActivityManagerProxy 的startService方法:
class ActivityManagerProxy implements IActivityManager {
......
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType) 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);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
......
}
参数service是一个Intent实例,它里面指定了要启动的服务的名称,也就是例子定义的服务名称“shy.luo.ashmem.server”了。
参数caller是一个IApplicationThread实例,它是一个在主进程创建的一个Binder对象。在Android应用程序中,每一个进程都用一个ActivityThread实例来表示,而在ActivityThread类中,有一个成员变量mAppThread,它是一个ApplicationThread实例,实现了IApplicationThread接口,它的作用是用来辅助ActivityThread类来执行一些操作(其实mAppThread是ActivityManagerService持有与App进程通信的Binder代理对象,ActivityManagerService利用调用IApplicationThread代理对象,实现通知ActivityThread执行对应的方法),这个我们在后面会看到它是如何用来启动服务的。
参数resolvedType是一个字符串,它表示service这个Intent的MIME类型,它是在解析Intent时用到的。在这个例子中,我们没有指定这个Intent 的MIME类型,因此,这个参数为null。
ActivityManagerProxy类的startService函数把这三个参数写入到data本地变量去,接着通过mRemote.transact函数进入到Binder驱动程序,然后Binder驱动程序唤醒正在等待Client请求的ActivityManagerService进程,最后进入到ActivityManagerService的startService函数中。
接下来就是ActivityManagerService会做一系列检查,然后通过socket方式通知Zygote孵化新的进程,指定新的进程加载ActivityThread类,并执行main方法。代码过程请参考我上一篇博文Android应用App启动流程。这里我们还是着重看一下Service在新的进程启动过程。
先看看ActivityThread的main方法:
public final class ActivityThread {
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
因为这段代码可以带我们了解App的启动和初始化过程,所以很重要。在这里初始化Looper,创建Looper和MessageQueue,然后调用attach方法,把自己的ApplicationThread代理对象通过IPC传给ActivityManagerService,调用Looper.loop方法,让Looper不断的从MessageQueue取出消息,实现消息机制。我们来看看attach方法(上一个博文没有写清楚attach方法,因为不清楚):
public final class ActivityThread {
......
private final void attach(boolean system) {
......
if (!system) {
......
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
}
} else {
......
}
......
}
......
}
主要是调用ActivityManagerService的代理对象ActivityManagerProxy的attachApplication的方法:
class ActivityManagerProxy implements IActivityManager {
......
public void attachApplication(IApplicationThread app) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
......
}
这下应该清楚知道ActivityThread怎么把ApplicationThread的代理对象传给ActivityManagerService了吧。我们顺便往下看,ActivityManagerService调用attachApplication的方法:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
......
}
attachApplicationLocked方法代码:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else if (mStartingProcesses.size() > 0) {
app = mStartingProcesses.remove(0);
app.setPid(pid);
} else {
app = null;
}
......
String processName = app.processName;
......
app.thread = thread;
......
boolean badApp = false;
......
// Find any services that should be running in this process...
if (!badApp && mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (app.info.uid != sr.appInfo.uid
|| !processName.equals(sr.processName)) {
continue;
}
mPendingServices.remove(i);
i--;
realStartServiceLocked(sr, app);
didSomething = true;
}
} catch (Exception e) {
......
}
}
......
return true;
}
......
}
最终调用realStartServiceLocked方法:
class ActivityManagerProxy implements IActivityManager {
......
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app) throws RemoteException {
......
r.app = app;
......
try {
......
app.thread.scheduleCreateService(r, r.serviceInfo);
......
} finally {
......
}
......
}
......
}
这里的app.thread是一个ApplicationThread的代理对象,通过调用这个代理对象scheduleCreateService方法,通知ActivityThread启动Service,回到App进程。
class ApplicationThreadProxy implements IApplicationThread {
......
public final void scheduleCreateService(IBinder token, ServiceInfo info)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
info.writeToParcel(data, 0);
mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
......
}
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
public final void scheduleCreateService(IBinder token,
ServiceInfo info) {
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
queueOrSendMessage(H.CREATE_SERVICE, s);
}
......
}
......
}
又见到熟悉的身形了,ApplicationThread作为ActivityThread内部类,直接代用queueOrSendMessage方法,分发消息到ActivityThread的MessageQueue,通知ActivityThread执行对应方法。所以整个Handler的消息机制,在Android中起了大多的作用。整个App运行,都是通过这个消息机制得以和谐运行,表示不禁感叹。上次都没看怎么ApplicationThread怎么分发消息,代码如下:
public final class ActivityThread {
......
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
......
}
很普通代码,通过Handler分发消息。看一下ActivityThread的Handler怎么处理启动Service的代码:
public final class ActivityThread {
......
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj);
break;
......
}
......
}
......
}
......
}
调用了handleCreateService方法:
public final class ActivityThread {
......
private final 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);
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 = new ContextImpl();
context.init(packageInfo, null, this);
Application app = packageInfo.makeApplication(false, mInstrumentation);
context.setOuterContext(service);
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, 0, 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);
}
}
}
......
}
这段代码主要是加载要启动的Service类,并执行service.onCreate()方法。至此,启动Service代码分析完毕。跟着老罗的代码解析,的确学习了不少。