标签:android 4.0 frameworks persistent
说说Android应用的persistent属性
侯 亮
在Android系统中,有一种永久性应用。它们对应的AndroidManifest.xml文件里,会将persistent属性设为true,比如:
<applicationandroid:name="PhoneApp" android:persistent="true" android:label="@string/dialerIconLabel" android:icon="@drawable/ic_launcher_phone">
在系统启动之时,AMS的systemReady()会加载所有persistent为true的应用。
publicvoid systemReady(finalRunnable goingCallback) { . . . . . . . . . . . . try{ List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); if(apps != null) { intN = apps.size(); inti; for(i=0; i<N; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); if(info != null&& !info.packageName.equals("android")) { addAppLocked(info,false); } } } } catch(RemoteException ex) { // pm is in same process, this will never happen. }
其中的STOCK_PM_FLAGS的定义如下:
// The flags that are set for all calls we make to the package manager. staticfinal int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
上面代码中的getPersistentApplications()函数的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public List<ApplicationInfo>
getPersistentApplications( int flags)
{ final ArrayList<ApplicationInfo>
finalList = new ArrayList<ApplicationInfo>(); //
reader synchronized (mPackages)
{ final Iterator<PackageParser.Package>
i = mPackages.values().iterator(); final int
userId = UserId.getCallingUserId(); while (i.hasNext())
{ final PackageParser.Package
p = i.next(); if (p.applicationInfo
!= null &&
(p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 &&
(!mSafeMode || isSystemApp(p))) { PackageSetting
ps = mSettings.mPackages.get(p.packageName); finalList.add(PackageParser.generateApplicationInfo(p,
flags, ps
!= null ?
ps.getStopped(userId) : false , ps
!= null ?
ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, userId)); } } } return finalList; } |
从代码里可以看出,带persistent标志的系统应用(即flags中设置了FLAG_SYSTEM)是一定会被选上的,但如果不是系统应用的话,则要进一步判断当前是否处于“安全模式”,一旦处于安全模式,那么就算应用设置了persistent属性,也不会被选中。
随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执行addAppLocked()。addAppLocked()的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
final ProcessRecord
addAppLocked(ApplicationInfo info, boolean isolated)
{ ProcessRecord
app; if (!isolated)
{ app
= getProcessRecordLocked(info.processName, info.uid); } else { app
= null ; } if (app
== null )
{ app
= newProcessRecordLocked( null ,
info, null ,
isolated); mProcessNames.put(info.processName,
app.uid, app); if (isolated)
{ mIsolatedProcesses.put(app.uid,
app); } updateLruProcessLocked(app, true , true ); } //
This package really, really can not be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( info.packageName, false ,
UserId.getUserId(app.uid)); } catch (RemoteException
e) { } catch (IllegalArgumentException
e) { Slog.w(TAG, "Failed
trying to unstop package " +
info.packageName + ":
"
+ e); } if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) ==
(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { app.persistent
= true ; app.maxAdj
= ProcessList.PERSISTENT_PROC_ADJ; } if (app.thread
== null &&
mPersistentStartingProcesses.indexOf(app) < 0 )
{ mPersistentStartingProcesses.add(app); startProcessLocked(app, "added
application" ,
app.processName); } return app; } |
现在,我们就清楚了,那些persistent属性为true的应用,基本上都是在系统启动伊始就启动起来的。
因为启动进程的过程是异步的,所以我们需要一个缓冲列表(即上面代码中的mPersistentStartingProcesses列表)来记录那些“正处于启动状态,而又没有启动完毕的”ProcessRecord结点。一旦目标进程启动完毕后,目标进程会attach系统,于是走到AMS的attachApplicationLocked(),在这个函数里,会把目标进程对应的ProcessRecord结点从mPersistentStartingProcesses缓冲列表里删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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; .
. . . . . thread.asBinder().linkToDeath(adr, 0 ); .
. . . . . thread.bindApplication(processName,
appInfo, providers, app.instrumentationClass,
profileFile, profileFd, profileAutoStop, app.instrumentationArguments,
app.instrumentationWatcher, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration),
app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); .
. . . . . .
. . . . . //
Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); .
. . . . . |
我们知道,persistent一词的意思是“持久”,那么persistent应用的意思又是什么呢?简单地说,这种应用会顽固地运行于系统之中,从系统一启动,一直到系统关机。
为了保证这种持久性,persistent应用必须能够在异常出现时,自动重新启动。在Android里是这样实现的。每个ActivityThread中会有一个专门和AMS通信的binder实体——final ApplicationThread mAppThread。这个实体在AMS中对应的代理接口为IApplicationThread。
当AMS执行到attachApplicationLocked()时,会针对目标用户进程的IApplicationThread接口,注册一个binder讣告监听器,一旦日后用户进程意外挂掉,AMS就能在第一时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应用是persistent的,它会尝试重新启动这个应用。
注册讣告监听器的代码如下:
1
2
3
|
AppDeathRecipient
adr = new AppDeathRecipient(app,
pid, thread); thread.asBinder().linkToDeath(adr, 0 ); app.deathRecipient
= adr; |
其中的thread就是IApplicationThread代理。
AppDeathRecipient的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
private final
class
AppDeathRecipient implements IBinder.DeathRecipient
{ final ProcessRecord
mApp; final int
mPid; final IApplicationThread
mAppThread; AppDeathRecipient(ProcessRecord
app, int pid, IApplicationThread
thread) { if (localLOGV)
Slog.v(TAG, "New
death recipient "
+ this + "
for thread "
+ thread.asBinder()); mApp
= app; mPid
= pid; mAppThread
= thread; } public void
binderDied() { if (localLOGV)
Slog.v(TAG, "Death
received in "
+ this + "
for thread "
+ mAppThread.asBinder()); synchronized (ActivityManagerService. this ) { appDiedLocked(mApp,
mPid, mAppThread); } } } |
当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。这个回调函数会辗转重启persistent应用,调用关系如下:
一般情况下,当一个应用进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的主要工作。然而,对于persistent应用,cleanUpApplicationRecordLocked()会尝试再次启动对应的应用进程。代码截选如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
private final
void
cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting,
boolean allowRestart,
int index)
{ .
. . . . . .
. . . . . if (!app.persistent
|| app.isolated) { .
. . . . . mProcessNames.remove(app.processName,
app.uid); mIsolatedProcesses.remove(app.uid); .
. . . . . } else if
(!app.removed) { if (mPersistentStartingProcesses.indexOf(app)
< 0 )
{ mPersistentStartingProcesses.add(app); restart
= true ; } } .
. . . . . .
. . . . . if (restart
&& !app.isolated) { mProcessNames.put(app.processName,
app.uid, app); startProcessLocked(app, "restart" ,
app.processName); } else if
(app.pid > 0 &&
app.pid != MY_PID) { .
. . . . . } .
. . . . . } |
现在我们可以画一张关于“启动persistent应用”的示意图:
在AMS中,有一个isAllowedWhileBooting()函数,其代码如下:
1
2
3
4
|
boolean isAllowedWhileBooting(ApplicationInfo
ai) { return (ai.flags
& ApplicationInfo.FLAG_PERSISTENT) != 0 ; } |
从这个函数可以看到,将persistent属性设为true的应用,是允许在boot的过程中启动的。我们可以查看前文提到的startProcessLocked()函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
final ProcessRecord
startProcessLocked(String processName, ApplicationInfo
info, boolean knownToBeDead,
int intentFlags, String
hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated)
{ ProcessRecord
app; if (!isolated)
{ app
= getProcessRecordLocked(processName, info.uid); } else { //
If this is an isolated process, it can‘t re-use an existing process. app
= null ; } .
. . . . . .
. . . . . if (!mProcessesReady &&
!isAllowedWhileBooting(info) &&
!allowWhileBooting) { if (!mProcessesOnHold.contains(app))
{ mProcessesOnHold.add(app); } if (DEBUG_PROCESSES)
Slog.v(TAG, "System
not ready, putting on hold: "
+ app); return app; } startProcessLocked(app,
hostingType, hostingNameStr); return (app.pid
!= 0 )
? app : null ; } |
其中的最后几句可以改写为以下更易理解的形式:
1
2
3
4
5
6
7
8
9
10
|
if (mProcessesReady
|| isAllowedWhileBooting(info) || allowWhileBooting) { startProcessLocked(app,
hostingType, hostingNameStr); return (app.pid
!= 0 )
? app : null ; } else { .
. . . . . return app; } |
也就是说,当系统已经处于以下几种情况时,多参数的startProcessLocked()会进一步调用另一个只有三个参数的startProcessLocked():
1)系统已经处于ready状态;
2)想要启动persistent应用;
3)参数中明确指定可以在boot过程中启动应用。
补充说一下,一般情况下,当AMS调用startProcessLocked()时,传入的allowWhileBooting参数都为false。比如说,当系统需要启动“某个content provider或者某个service或者某个特定activity”时,此时传给startProcessLocked()的allowWhileBooting参数是写死为false的。只有一种特殊情况下会在该参数中传入true,那就是当系统发出的广播intent中携带有Intent.FLAG_RECEIVER_BOOT_UPGRADE标记时,此时允许在系统未ready时,启动接受广播的目标进程。
有关Android应用的persistent属性,我们就先说这么多。希望对大家有点儿帮助。
标签:android 4.0 frameworks persistent
原文地址:http://blog.csdn.net/codefly/article/details/42339981