Android启动早于系统应用的第三方应用,杀不死自动重启的第三方应用

1.为什么第三方应用能早于System的app启动?

Android应用的启动顺序网上有一大堆资料可以查阅了,这里就不细述了,这里不阐述ROM启动还有bootloader,软件启动的大致流程应该是

  • 启动kernel
  • 运行servicemanager 把一些native的服务用命令启动起来(包括wifi, power, rild, surfaceflinger, mediaserver等等)
  • 启动Dalivk中的第一个进程Zygote -> 启动java 层的系统服务system_server(包括PowerManagerService, ActivityManagerService , telephony.registry, DisplayManagerService等等)该服务中的这些部件跟native的那些服务关联在一起
  • 启动Luncher和Persistent的App,该程序是系统级的在AndroidManifest.xml里声明android:persistent="true"
  • 发出ACTION_BOOT_COMPLETED广播给其他应用。

在这里需要注意的是声明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的属性如下:

       <receiver android:name="com.anguanjia.safe.AAAReceiver">
            <span style="color:#FF0000;"><intent-filter android:priority="2147483647"></span>
                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
                <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.intent.action.ANY_DATA_STATE" />
                <action android:name="android.net.wifi.STATE_CHANGE" />
            </intent-filter>
            <intent-filter android:priority="2147483647">
                <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
                <action android:name="android.intent.action.MEDIA_MOUNTED" />
                <action android:name="android.intent.action.MEDIA_REMOVED" />
                <action android:name="android.intent.action.MEDIA_CHECKING" />
                <action android:name="android.intent.action.MEDIA_EJECT" />
                <data android:scheme="file" />
            </intent-filter>

2147483647 这个值是什么?好大,哦,原来是int的最大值!我们来看下google 文档

android:priority

The priority that should be given to the parent component with regard to handling intents of the type described by the filter. This attribute has meaning for both activities and broadcast receivers:

It provides information about how able an activity is to respond to an intent that matches the filter, relative to other activities that could also respond to the intent. When an intent could be handled by multiple activities with different priorities,
Android will consider only those with higher priority values as potential targets for the intent.

It controls the order in which broadcast receivers are executed to receive broadcast messages. Those with higher priority values are called before those with lower values. (The order applies only to synchronous messages; it‘s ignored for asynchronous
messages.)

Use this attribute only if you really need to impose a specific order in which the broadcasts are received, or want to force Android to prefer one activity over others.

The 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的启动的情况。

2. 在Android手机上为什么我想完全关闭的程序关不了?

有一种理论是Android手机为了有更好的用户体验,会后台自动启动一些程序, 这样我们前台在操作的时候会感觉手机更流畅平滑。但是如果程序运行过多,对CPU 内存的开销过大,往往会导致系统越用越慢,乃至手机挂掉的问题,在内存管理这快Android有两种机制去解决这个问题,一个是在framework层在 trimApplication方法中去实现,另外一个就是在kernel里的lowmemorykiller, 这里不再细述。

但是对于用户来说,我就是想完全关闭第三方程序,以免过多使用我的流量或者偷偷的做一些我不希望的操作。貌似没有办法去关闭,那为什么呢? 我这里先讲述其中一种情况。

Service顾名思义是服务,运行在前后台后都可以,即可以运行在当前进程也可以运行在其他的进程里,Service可以为多个APP共享使用,是通过binder机制来实现的。当我Kill掉一个带有服务的进程(没有调用stopService()), 过一会该应用会自动重启。下面是代码的调用顺序,自下往上查看。

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 <span style="color:#FF0000;"><strong>onStartCommand</strong></span>(Intent intent, int flags, int startId) {
        return <span style="color:#FF0000;"><strong>START_NOT_STICKY</strong></span>;
    }

Framwork实现代码

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.<span style="color:#FF0000;">stopIfKilled</span> = true;   // 该变量设置为true
                        }
                        break;
                    }

                if (sr.startRequested && (sr.<span style="color:#FF0000;">stopIfKilled</span> || 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的去处理。

Android启动早于系统应用的第三方应用,杀不死自动重启的第三方应用

时间: 2024-08-09 06:55:09

Android启动早于系统应用的第三方应用,杀不死自动重启的第三方应用的相关文章

init进程 &amp;&amp; 解析Android启动脚本init.rc &amp;&amp; 修改它使不启动android &amp;&amp; init.rc中启动一个sh文件

Android启动后,系统执行的第一个进程是一个名称为init 的可执行程序.提供了以下的功能:设备管理.解析启动脚本.执行基本的功能.启动各种服务.代码的路径:system/core/init,编译的结果是一个可执行文件:init.这个init 的可执行文件是系统运行的第一个用户空间的程序,它以守护进程的方式运行.启动脚本则就是下面要讲的Init.rc. ======================================================================

android启动之ServiceManager启动

其实init进程启动后,ServiceManager进程的启动,远比zygote要早,因为在启动zygote进程时需要用到ServiceManager进程的服务.ServiceManager是一个守护进程,它维护着系统服务和客户端的binder通信. 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binder驱动程序组成.其中Client.Service和ServiceManager运行在用户空间,而Bind

android启动之SystemServer启动

SystemServer是Android系统的核心,APK应用中能够直接交互的大部分系统服务都在该进程中运行,常见的比如WindowManagerServer(Wms).ActivityManagerSystemService(AmS). PackageManagerServer(PmS)等,这些系统服务都是以一个线程的方式存在于SystemServer进程中. startSystemServer systemServer是通过zygote启动的时候fork启动的,我们先看回到ZygoteIni

android启动之init启动

整个Android系统的启动分为Linux kernel的启动和Android系统的启动.Linux kernel启动起来后,然后就运行第一个用户程序,在Android中,就是init程序,上一博文已经介绍. Init进程始终是第一个进程.Init进程的对应的代码的main函数在目录system/core/init/init.c,先来总体看一下这个main函数. main函数 int main(int argc, char **argv) { //首先声明一些局部变量 int fd_count

Android 4.1 Audio系统变化说明

转自Android 4.1 Audio系统变化说明 Android 4.1,英文代号简称JB.在国人眼里,JB这个词还和动物有点关系.Google如此频繁修改Android,终于推出了一个可以被大家整天JB JB挂在嘴上的版本.以后我的文章也可以一面用JB表示版本号,一面用JB表示毛主席常说的"战略上的鄙视了".请大家根据上下文揣摩我写下JB一词的心情. 今天将稍深入得介绍一下JB 4.1在Audio系统做的翻天覆地的改动.这里先啰嗦几句:就像80后经常抱怨自己晚生了几年一样,马上就会

Android启动过程

Android启动过程 1.  加载Linux内核 2. Android init进程对各种设备进行初始化,运行Android Framework所需用的各种Daemon(后台进程/守护进程),Context Manager,MediaServer,Zygote等 以下是init进程执行的Daemon进程: USB Daemon(usbd): 管理USB连接 Android Debug Bridge Daemon(adbd): Android  Debug Bridge连接管理 Debugger

android启动之子系统切换

转载请注明文章出处和作者! 出处:http://blog.csdn.net/xl19862005 大家多多支持偶家媳妇的网店:http://wen1991.taobao.com 作者:大熊(Xandy) 1.总述 在android系统中有好几个子系统(recovery.factory及power off charge),那么这些子系统是如何与主系统之间进行切换的呢? (recovery系统的切换与启动已经在另一篇博客里写过了 http://blog.csdn.net/xl19862005/art

android启动之zygote启动

上一博文介绍了init进程启动,在解析init.rc 的时候会把zygote加到service列表中,并最终启动,zygote启动的实际是app_process程序.zygote是init进程的子进程.在Android系统中,所有的应用程序以及系统服务,包括SystemServer都是由Zygote fork出来的,这就是为什么它叫zygote(受精卵)的原因.我们再来看一下.rc文件的描述: service zygote /system/bin/app_process -Xzygote /sy

android130 android启动

Android的编译环境只支持Linux和Mac OS,google推荐使用64位操作系统, ### android启动 > #### 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统同时会加载用户级别的第一个进程init(system\core\init.c)代码如下: int main(int argc, char **argv) { // 创建文件夹 挂载 mount("tmpfs", "/dev",