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()函数的定义如下:
publicList
{
finalArrayList
//reader
synchronized(mPackages)
{
finalIterator
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小时内删除。
留言与评论(共有 0 条评论) |