Android应⽤的persistent属性
摘要: 在Android系统中,有⼀种永久性应⽤。它们对应的l⽂件⾥,会将persistent属性设为true。
中文简体转繁体说说Android应⽤的persistent属性
侯 亮
1 启动persistent应⽤
在Android系统中,有⼀种永久性应⽤。它们对应的l⽂件⾥,会将persistent属性设为true,⽐如:
<application android:name="PhoneApp"
android:persistent="true"
android:label="@string/dialerIconLabel"
android:icon="@drawable/ic_launcher_phone">
在系统启动之时,AMS的systemReady()会加载所有persistent为true的应⽤。
public void systemReady(final Runnable goingCallback)
{centre
. . . . . .
. . . . . .
try {
List apps = PackageManager().
getPersistentApplications(STOCK_PM_FLAGS);
if (apps != null)
{
int N = apps.size();
int i;
for (i=0; i<N; i++)
{
ApplicationInfo info = ((i);
if (info != null &&
!info.packageName.equals("android"))
{
addAppLocked(info, fal);
}
}
}
}
catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
其中的STOCK_PM_FLAGS的定义如下:
// The flags that are t for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
上⾯代码中的getPersistentApplications()函数的定义如下:
public List<ApplicationInfo> getPersistentApplications(int flags)
{
final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
/
/ reader
synchronized (mPackages)
{
final Iterator<PackageParr.Package> i = mPackages.values().iterator();
final int urId = CallingUrId();
while (i.hasNext())
{
final PackageParr.Package p = i.next();
if (p.applicationInfo != null
&& (p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p)))
{
promote是什么意思
PackageSetting ps = (p.packageName);
finalList.ateApplicationInfo(p, flags,
ps != null ? ps.getStopped(urId) : fal,
ps != null ? ps.getEnabled(urId) : COMPONENT_ENABLED_STATE_DEFAULT,
urId));
}
}
}
return finalList;
}
在PKMS中,有⼀个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息,该信息的flags(int 型)数据中有⼀个专门的bit⽤于表⽰persistent。getPersistentApplications()函数会遍历这张表,找出所有persistent包,并返回ArrayList<ApplicationInfo>。
从代码⾥可以看出,带persistent标志的系统应⽤(即flags中设置了FLAG_SYSTEM)是⼀定会被选上的,但如果不是系统应⽤的话,则要进⼀步判断当前是否处于“安全模式”,⼀旦处于安全模式,那么就算应⽤设置了persistent属性,也不会被选中。
随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执⾏addAppLocked()。addAppLocked()的代码如下:
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated)
{
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(info.processName, info.uid);
} el {
app = null;
}
if (app == null) {
app = newProcessRecordLocked(null, info, null, isolated);
fuxmProcessNames.put(info.processName, app.uid, app);
if (isolated) {
mIsolatedProcess.put(app.uid, app);
}
updateLruProcessLocked(app, true, true);
}
/
/ This package really, really can not be stopped.
try {
info.packageName, fal, UrId(app.uid));casting什么意思
} 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 && mPersistentStartingProcess.indexOf(app) < 0) {
mPersistentStartingProcess.add(app);
startProcessLocked(app, "added application", app.processName);
}
return app;
}
美女与野兽 歌曲
在AMS中,所谓的“add App”主要是指“添加⼀个与App进程对应的ProcessRecord节点”。当然,如果该节点已经添加过了,那么是不会重复添加的。在添加节点的动作完成以后,addAppLocked()还会检查App进程是否已经启动好了,如果尚未开始启动,此时就会调⽤startProcessLocked()启动这个进程。
既然addAppLocked()试图确认App“正在正常运作”或者“将被正常启动”,那么其对应的package就不可能处于stopped状态,这就是上⾯代码调⽤tPackageStoppedState(...,fal,...)的意思。
现在,我们就清楚了,那些persistent属性为true的应⽤,基本上都是在系统启动伊始就启动起来的。
因为启动进程的过程是异步的,所以我们需要⼀个缓冲列表(即上⾯代码中的mPersistentStartingProcess列表)来记录那些“正处于启动状态,⽽⼜没有启动完毕的”ProcessRecord结点。⼀旦⽬标进程启动完毕后,⽬标进程会attach系统,于是⾛到AMS的attachApplicationLocked(),在这个函数⾥,会把⽬标进程对应的ProcessRecord结点从mPersistentStartingProcess缓冲列表⾥删除。
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
// Find the application record that is either via
// the pid if we are running in multiple process, 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), pat,
getCommonServicesLocked(),
.
. . . . .
. . . . . .
// Remove this record from the list of starting applications.
. . . . . .superblock
2 如何保证应⽤的持久性(persistent)
我们知道,persistent⼀词的意思是“持久”,那么persistent应⽤的意思⼜是什么呢?简单地说,这种应⽤会顽固地运⾏于系统之中,从系统⼀启动,⼀直到系统关机。
为了保证这种持久性,persistent应⽤必须能够在异常出现时,⾃动重新启动。在Android⾥是这样实现的。每个ActivityThread中会有⼀个专门和AMS通信的binder实体——final ApplicationThread mAppThread。这个实体在AMS中对应的代理接⼝为IApplicationThread。uid是什么意思
当AMS执⾏到attachApplicationLocked()时,会针对⽬标⽤户进程的IApplicationThread接⼝,注册⼀
个binder讣告监听器,⼀旦⽇后⽤户进程意外挂掉,AMS就能在第⼀时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应⽤是persistent的,它会尝试重新启动这个应⽤。
注册讣告监听器的代码如下:
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
其中的thread就是IApplicationThread代理。
AppDeathRecipient的定义如下:
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);
}
}melee
}
当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。这个回调函数会辗转重启persistent应⽤,调⽤关系如下:
⼀般情况下,当⼀个应⽤进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的主要⼯作。然⽽,对于persistent应⽤,cleanUpApplicationRecordLocked()会尝试再次启动对应的应⽤进程。代码截选如下: