Android应用的启动顺序网上有一大堆资料可以查阅了,这里就不细述了,这里不阐述ROM启动还有bootloader,软件启动的大致流程应该是
在这里需要注意的是声明android:persistent属性为true的APP被kill掉后还是会自动重启的。系统中我们已知android:persistent属性为true的APP肯定有Phone App,也就是说第三方应用应当至少晚于Phone APP启动,如何判断呢?最简单的办法看其PID的大小,PID值越小越先启动。有其第三方应用可以先于Phone APP启动。我们探其应用的AndroidManifest.xml (PS:如何看APK的代码,网上有你懂的apktool等),发现其在AndroidManifest里定义的静态Receiver的intent-filter的属性如下:
2147483647 这个值是什么?好大,哦,原来是int的最大值!我们来看下google 文档
android:priorityThe value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.
这个值是receiver的优先级,值越大优先级越高,按优先顺序执行,但是文档介绍优先级值大小是 -1000~1000. 该应用的是int的最大值, 但android平台没有对android:priority值进行检查。在开机后该应用Receiver的intent-filter的优先级最高,在该filter里的intent被系统发送出来(android.intent.action.MEDIA_MOUNTE, android.net.wifi.WIFI_STATE_CHANGED等等),这个时候App会根据这个intent而被启动起来。这里需要注意的是该Receiver是个静态的,一定是要注册在AndroidManifest里。当Wifi成功注册后会发出WIFI_STATE_CHANGED的消息, 或者其他的部件完成一些事件后也会发出类似的消息,而这些消息的发出又早于属性为persistent的系统级APP的启动, 由此就会发生第三方应用早于系统级APP的启动的情况。
com.android.server.am.ActiveServices.scheduleServiceRestartLocked(ActiveServices.java)
com.android.server.am.ActiveServices.killServicesLocked (ActiveServices.java)
com.android.server.am.ActivityManagerService.cleanUpApplicationRecordLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.handleAppDiedLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.appDiedLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java)
从代码流程上我们看出该service被restart,进程也根据该service启动起来, service就运行在重启的进程里。
在这种情况下是不是就真没办法了呢,当然不是,如果我们在service中覆盖onStartCommand这个函数并且返回值为START_NOT_STICKY,在我们kill该进程后则不会自动重启,我们想关闭的应用也可以完全关闭了,不会再自动重启了。
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
frameworks/base/services/java/com/android/server/am/ActiveServices.java
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
if (r.getLastStartId() == startId) {
// There is no more work, and this service
// doesn't want to hang around if killed.
r.stopIfKilled = true; // 该变量设置为true
}
break;
}
if (sr.startRequested && (sr.stopIfKilled || canceled)) { //进入到该条件中
if (sr.pendingStarts.size() == 0) {
sr.startRequested = false;
if (sr.tracker != null) {
sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
if (!sr.hasAutoCreateConnections()) {
// Whoops, no reason to restart!
bringDownServiceLocked(sr); //执行在这里,不会重启App
}
}
}
重写onStartCommand方法且返回值为START_NOT_STICKY的代码调用顺序,自下而上查看。
com.android.server.am.ActiveServices.bringDownServiceLocked(ActiveServices.java)
com.android.server.am.ActiveServices.killServicesLocked(ActiveServices.java)
com.android.server.am.ActivityManagerService.cleanUpApplicationRecordLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.handleAppDiedLocked(ActivityManagerService.java)
com.android.server.am.ActivityManagerService.appDiedLocked(Activi tyManagerService.java)
com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java)
附上Google doc 对于onStartCommand返回值的说明For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand():START_STICKY
is used for services that are explicitly started and stopped as needed, whileSTART_NOT_STICKY
orSTART_REDELIVER_INTENT
are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
在这里对这个返回值做下解释:
当服务进程因某种原因(内存不够,强制关闭等)被kill掉时,START_STICKY在系统有充足的内存后重新创建service, 在onStartCommand中handle的是null intent.
START_NOT_STICKY通知系统不在重新创建该service. 还有一个返回值START_REDELIVER_INTENT重新创建service并且伴随着原来intent的去处理。