persist

更新时间:2023-01-04 03:55:09 阅读: 评论:0


2023年1月4日发(作者:亮堂)

Android应⽤的persistent属性

摘要:在Android系统中,有⼀种永久性应⽤。它们对应的⽂件⾥,会将persistent属性设为true。

说说Android应⽤的persistent属性

侯亮

1启动persistent应⽤

在Android系统中,有⼀种永久性应⽤。它们对应的⽂件⾥,会将persistent属性设为true,⽐如:

android:persistent="true"

android:label="@string/dialerIconLabel"

android:icon="@drawable/ic_launcher_phone">

在系统启动之时,AMS的systemReady()会加载所有persistent为true的应⽤。

publicvoidsystemReady(finalRunnablegoingCallback)

{

......

......

try{

Listapps=kageManager().

getPersistentApplications(STOCK_PM_FLAGS);

if(apps!=null)

{

intN=();

inti;

for(i=0;i

{

ApplicationInfoinfo=(ApplicationInfo)(i);

if(info!=null&&

!("android"))

{

addAppLocked(info,fal);

}

}

}

}

catch(RemoteExceptionex){

//pmisinsameprocess,thiswillneverhappen.

}

其中的STOCK_PM_FLAGS的定义如下:

//Theflagsthataretforallcallswemaketothepackagemanager.

staticfinalintSTOCK_PM_FLAGS=_SHARED_LIBRARY_FILES;

上⾯代码中的getPersistentApplications()函数的定义如下:

publicListgetPersistentApplications(intflags)

{

finalArrayListfinalList=newArrayList();

//reader

synchronized(mPackages)

{

finalIteratori=().iterator();

finalinturId=lingUrId();

while(t())

{

ep=();

if(ationInfo!=null

&&(&_PERSISTENT)!=0

&&(!mSafeMode||isSystemApp(p)))

{

PackageSettingps=(eName);

(teApplicationInfo(p,flags,

ps!=null?pped(urId):fal,

ps!=null?bled(urId):COMPONENT_ENABLED_STATE_DEFAULT,

urId));

}

}

}

returnfinalList;

}

在PKMS中,有⼀个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息,该信息的flags(int

型)数据中有⼀个专门的bit⽤于表⽰persistent。getPersistentApplications()函数会遍历这张表,找出所有persistent包,并返回

ArrayList

从代码⾥可以看出,带persistent标志的系统应⽤(即flags中设置了FLAG_SYSTEM)是⼀定会被选上的,但如果不是系统应⽤的

话,则要进⼀步判断当前是否处于“安全模式”,⼀旦处于安全模式,那么就算应⽤设置了persistent属性,也不会被选中。

随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执⾏addAppLocked()。addAppLocked()

的代码如下:

finalProcessRecordaddAppLocked(ApplicationInfoinfo,booleanisolated)

{

ProcessRecordapp;

if(!isolated){

app=getProcessRecordLocked(sName,);

}el{

app=null;

}

if(app==null){

app=newProcessRecordLocked(null,info,null,isolated);

(sName,,app);

if(isolated){

(,app);

}

updateLruProcessLocked(app,true,true);

}

//Thispackagereally,reallycannotbestopped.

try{

kageManager().tPackageStoppedState(

eName,fal,rId());

}catch(RemoteExceptione){

}catch(IllegalArgumentExceptione){

Slog.w(TAG,"Failedtryingtounstoppackage"

+eName+":"+e);

}

if((&(_SYSTEM|_PERSISTENT))

==(_SYSTEM|_PERSISTENT)){

tent=true;

=TENT_PROC_ADJ;

}

if(==null&&f(app)<0){

(app);

startProcessLocked(app,"addedapplication",sName);

}

returnapp;

}

在AMS中,所谓的“addApp”主要是指“添加⼀个与App进程对应的ProcessRecord节点”。当然,如果该节点已经添加过了,那

么是不会重复添加的。在添加节点的动作完成以后,addAppLocked()还会检查App进程是否已经启动好了,如果尚未开始启动,此时就会

调⽤startProcessLocked()启动这个进程。既然addAppLocked()试图确认App“正在正常运作”或者“将被正常启动”,那么其对应的

package就不可能处于stopped状态,这就是上⾯代码调⽤tPackageStoppedState(...,fal,...)的意思。

现在,我们就清楚了,那些persistent属性为true的应⽤,基本上都是在系统启动伊始就启动起来的。

因为启动进程的过程是异步的,所以我们需要⼀个缓冲列表(即上⾯代码中的mPersistentStartingProcess列表)来记录那些“正处

于启动状态,⽽⼜没有启动完毕的”ProcessRecord结点。⼀旦⽬标进程启动完毕后,⽬标进程会attach系统,于是⾛到AMS的

attachApplicationLocked(),在这个函数⾥,会把⽬标进程对应的ProcessRecord结点从mPersistentStartingProcess缓冲列表⾥

删除。

privatefinalbooleanattachApplicationLocked(IApplicationThreadthread,intpid){

//Findtheapplicationrecordthatisbeingattached...eithervia

//thepidifwearerunninginmultipleprocess,orjustpullthe

//nextapprecordifweareemulatingprocesswithanonymousthreads.

ProcessRecordapp;

......

er().linkToDeath(adr,0);

......

plication(processName,appInfo,providers,

mentationClass,profileFile,profileFd,profileAutoStop,

mentationArguments,mentationWatcher,testMode,

enableOpenGlTrace,isRestrictedBackupMode||!normalMode,

tent,

newConfiguration(mConfiguration),,

getCommonServicesLocked(),

eSettingsLocked());

......

......

//Removethisrecordfromthelistofstartingapplications.

(app);

......

2如何保证应⽤的持久性(persistent)

我们知道,persistent⼀词的意思是“持久”,那么persistent应⽤的意思⼜是什么呢?简单地说,这种应⽤会顽固地运⾏于系统之中,

从系统⼀启动,⼀直到系统关机。

为了保证这种持久性,persistent应⽤必须能够在异常出现时,⾃动重新启动。在Android⾥是这样实现的。每个ActivityThread中会有

⼀个专门和AMS通信的binder实体——finalApplicationThreadmAppThread。这个实体在AMS中对应的代理接⼝为

IApplicationThread。

当AMS执⾏到attachApplicationLocked()时,会针对⽬标⽤户进程的IApplicationThread接⼝,注册⼀个binder讣告监听器,⼀旦⽇

后⽤户进程意外挂掉,AMS就能在第⼀时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应⽤是persistent的,它会尝试重新启

动这个应⽤。

注册讣告监听器的代码如下:

AppDeathRecipientadr=newAppDeathRecipient(app,pid,thread);

er().linkToDeath(adr,0);

ecipient=adr;

其中的thread就是IApplicationThread代理。

AppDeathRecipient的定义如下:

ecipient

{

finalProcessRecordmApp;

finalintmPid;

finalIApplicationThreadmAppThread;

AppDeathRecipient(ProcessRecordapp,intpid,

IApplicationThreadthread)

{

if(localLOGV)

Slog.v(TAG,"Newdeathrecipient"+this

+"forthread"+er());

mApp=app;

mPid=pid;

mAppThread=thread;

}

publicvoidbinderDied()

{

if(localLOGV)

Slog.v(TAG,"Deathreceivedin"+this

+"forthread"+er());

synchronized()

{

appDiedLocked(mApp,mPid,mAppThread);

}

}

}

当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。这个回调函数会辗转重启persistent应⽤,调⽤关系如

下:

⼀般情况下,当⼀个应⽤进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的

主要⼯作。然⽽,对于persistent应⽤,cleanUpApplicationRecordLocked()会尝试再次启动对应的应⽤进程。代码截选如下:

privatefinalvoidcleanUpApplicationRecordLocked(ProcessRecordapp,booleanrestarting,booleanallowRestart,intindex)

{

......

......

if(!tent||ed)

{

......

(sName,);

();

......

}

elif(!d)

{

if(f(app)<0){

(app);

restart=true;

}

}

......

......

if(restart&&!ed)

{

(sName,,app);

startProcessLocked(app,"restart",sName);

}

elif(>0&&!=MY_PID)

{

......

}

......

}

现在我们可以画⼀张关于“启动persistent应⽤”的⽰意图:

3补充知识点

3.1persistent应⽤可以在系统未准备好时启动

在AMS中,有⼀个isAllowedWhileBooting()函数,其代码如下:

booleanisAllowedWhileBooting(ApplicationInfoai)

{

return(&_PERSISTENT)!=0;

}

从这个函数可以看到,将persistent属性设为true的应⽤,是允许在boot的过程中启动的。我们可以查看前⽂提到的

startProcessLocked()函数:

finalProcessRecordstartProcessLocked(StringprocessName,ApplicationInfoinfo,booleanknownToBeDead,intintentFlags,StringhostingType,ComponentNam

{

ProcessRecordapp;

if(!isolated)

{

app=getProcessRecordLocked(processName,);

}

el

{

//Ifthisisanisolatedprocess,itcan'tre-uanexistingprocess.

app=null;

}

......

......

if(!mProcessReady

&&!isAllowedWhileBooting(info)

&&!allowWhileBooting){

if(!ns(app)){

(app);

}

if(DEBUG_PROCESSES)Slog.v(TAG,"Systemnotready,puttingonhold:"+app);

returnapp;

}

startProcessLocked(app,hostingType,hostingNameStr);

return(!=0)?app:null;

}

其中的最后⼏句可以改写为以下更易理解的形式:

if(mProcessReady||isAllowedWhileBooting(info)||allowWhileBooting)

{

startProcessLocked(app,hostingType,hostingNameStr);

return(!=0)?app:null;

}

el

{

......

returnapp;

}

也就是说,当系统已经处于以下⼏种情况时,多参数的startProcessLocked()会进⼀步调⽤另⼀个只有三个参数的

startProcessLocked():

1)系统已经处于ready状态;

2)想要启动persistent应⽤;

3)参数中明确指定可以在boot过程中启动应⽤。

补充说⼀下,⼀般情况下,当AMS调⽤startProcessLocked()时,传⼊的allowWhileBooting参数都为fal。⽐如说,当系统需要启

动“某个contentprovider或者某个rvice或者某个特定activity”时,此时传给startProcessLocked()的allowWhileBooting参数是写

死为fal的。只有⼀种特殊情况下会在该参数中传⼊true,那就是当系统发出的⼴播intent中携带有

_RECEIVER_BOOT_UPGRADE标记时,此时允许在系统未ready时,启动接受⼴播的⽬标进程。

4结束

有关Android应⽤的persistent属性,我们就先说这么多。希望对⼤家有点⼉帮助。

本文发布于:2023-01-04 03:55:09,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/88451.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:brilliantly
标签:persist
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图