在Android程序开发时我们会接触到一些系统为了某些功能而定义的关键属性,例如在AndroidManifest.xml文件中

经常看到的persistent、process等,下面是自己对persistent关键字的分析,直奔主题。

一、persistent属性作用

1、定义

该属性的定义在frameworks/base/core/res/res/values/attrs_manifest.xml中,其定义如下:

<!-- Flag to control special persistent mode of an application.  This shouldnot normally be used by applications; it requires that the system keepyour application running at all times. --><attr name="persistent" format="boolean" />

通过官方注释我知道该属性用于是否让你的应用一直处于运行状态(通常说的常驻内存)。设置
该属性为true的app具有如下特点:

  • 在系统启动的时候会被系统启动起来

  • 在该app被强制杀掉后系统会重新启动该app,这种情况只针对系统内置app,第三方安装的app不会被重启

2、使用

persistent属性是用于application标签上的,用法为:

AndroidManifest.xml


<application    android:persistent="true|false"></application>

persistent的值默认为false

二、原理分析

通过第一点对persistent的功能说明后我们通过源码来分析一下它的工作原理

1、persistent属性的解析

该属性的解析主要在app被安装或者系统启动的时候发生

解析代码:

frameworks/base/core/java/com/android/content/pm/PackageParser.java


private boolean parseBaseApplication(Package owner, Resources res,XmlResourceParser parser, int flags, String[] outError)throws XmlPullParserException, IOException {final ApplicationInfo ai = owner.applicationInfo;//.......................if ((flags&PARSE_IS_SYSTEM) != 0) {if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifestApplication_persistent,false)) {ai.flags |= ApplicationInfo.FLAG_PERSISTENT;}}//.............}

在解析完包信息之后系统会将解析好的所有包信息存放到PKMS中的mPackages的map中,而ApplicationInfo的flag中有一个bit位用于保存该app是否是persistent的。这里只是把保存persistent的flag设置为FLAG_PERSISTENT。在AndroidManifest设置了persistent为true的app是否能够在被异常杀死后能够得到重启的权力需要取决于该app对应的ProcessRecord的persistent属性,该属性只有在你的app既在AndroidManifest中配置了persistent=“true”,又是系统内置app时才会被设置为true。

2、系统启动时启动persistent为true的app

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

在系统启动时ActivityManagerService的systemReady()方法会将所有在AndroidManifest设置了persistent为true的app拉起来

public void systemReady(final Runnable goingCallback) {......synchronized (this) {// Only start up encryption-aware persistent apps; once user is// unlocked we'll come back around and start unaware appsstartPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);// Start up initial activity.mBooting = true;// Enable home activity for system user, so that the system can always bootif (UserManager.isSplitSystemUser()) {ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);try {AppGlobals.getPackageManager().setComponentEnabledSetting(cName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,UserHandle.USER_SYSTEM);} catch (RemoteException e) {throw e.rethrowAsRuntimeException();}}......}

systemReady中调用了startPersistentApps() 方法


private void startPersistentApps(int matchFlags) {if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;synchronized (this) {try {final List<ApplicationInfo> apps = AppGlobals.getPackageManager().getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();for (ApplicationInfo app : apps) {if (!"android".equals(app.packageName)) {addAppLocked(app, false, null /* ABI override */);}}} catch (RemoteException ex) {}}}

在startPersistentApps方法中首先是调用PackageManageServices的getPersistentApplications方法获取到所有在AndroidManifest设置了persistent为true的app,然后调用addAppLocked方法去启动他们。这样在AndroidManifest设置了persistent为true的app就随着系统的启动而启动了。
下面看一下getPersistentApplications方法,该方法调用了PKMS中的getPersistentApplicationsInternal方法。

private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();// readersynchronized (mPackages) {final Iterator<PackageParser.Package> i = mPackages.values().iterator();final int userId = UserHandle.getCallingUserId();while (i.hasNext()) {final PackageParser.Package p = i.next();if (p.applicationInfo == null) continue;final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)&& !p.applicationInfo.isDirectBootAware();final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)&& p.applicationInfo.isDirectBootAware();if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0&& (!mSafeMode || isSystemApp(p))&& (matchesUnaware || matchesAware)) {PackageSetting ps = mSettings.mPackages.get(p.packageName);if (ps != null) {ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,ps.readUserState(userId), userId);if (ai != null) {finalList.add(ai);}}}}}return finalList;}

该方法会遍历mPackages中的所有app,并找到其中在AndroidManifest设置了persistent为true的应用。从代码中可以看到,persistent为true并且是系统app的话一定会被选中,但是如果是第三方安装的应用的话只能在非“安全模式”下才会被选中。

之后调用addAppLocked方法启动app:

    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,String abiOverride) {ProcessRecord app;//传递进来的isolated=false,所有一定会调用getProcessRecordLocked方法,但是由于是第一次启动,所有返回的app = nullif (!isolated) {app = getProcessRecordLocked(info.processName, info.uid, true);} else {app = null;}if (app == null) {//为新的app创建新的ProcessRecord对象app = newProcessRecordLocked(info, null, isolated, 0);updateLruProcessLocked(app, false, null);updateOomAdjLocked();}// This package really, really can not be stopped.try {//由于是开机第一次启动,所以新的app的启动状态是将要被启动状态,所以//该app的停止状态stoped被设置为falseAppGlobals.getPackageManager().setPackageStoppedState(info.packageName, false, UserHandle.getUserId(app.uid));} catch (RemoteException e) {} catch (IllegalArgumentException e) {Slog.w(TAG, "Failed trying to unstop package "+ info.packageName + ": " + e);}//在这里对persistent的app进行过滤,只有既是系统app,persistent为true的app才会在//异常死亡之后被重启if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {app.persistent = true;app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;}//如果该app已经启动了,则不用处理,否则调用startProcessLocked方法启动app。//由于启动app是异步进行的,会将正在启动而还没有启动完成的app添加到//mPersistentStartingProcesses列表中。当启动完成后 再移除if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {mPersistentStartingProcesses.add(app);//启动该appstartProcessLocked(app, "added application", app.processName, abiOverride,null /* entryPoint */, null /* entryPointArgs */);}return app;}}

接下来调用startProcessLocked方法启动app进程,在app启动完成后会在ActivityThread中调用AMS的attachApplication,将该app从mPersistentStartingProcesses中移除,并注册一个死亡讣告监听器AppDeathRecipient,用于在app异常被杀后的处理工作。


private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {......try {//注册死亡讣告监听器AppDeathRecipientAppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);thread.asBinder().linkToDeath(adr, 0);app.deathRecipient = adr;} catch (RemoteException e) {app.resetPackageList(mProcessStats);startProcessLocked(app, "link fail", processName);return false;}......}

3、app被异常结束后系统重新启动persistent为true的app

进程启动时为app注册了一个死亡讣告,当该app被杀掉之后会调用AppDeathRecipient的binderDied方法,该方法会调用appDiedLocked方法进行善后处理,系统在进程死掉之后会对死掉的进程进行清理和资源回收,但是在这个过程中如果你的app是persistent的话会被重启:

binderDied

  ||——appDiedLocked||——handleAppDiedLocked||——cleanUpApplicationRecordLocked

在cleanUpApplicationRecordLocked中对persistent为true的app进行重启

private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,boolean restarting, boolean allowRestart, int index, boolean replacingPid) {...............//非persistent的app被杀死后就被清理掉if (!app.persistent || app.isolated) {if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,"Removing non-persistent process during cleanup: " + app);if (!replacingPid) {removeProcessNameLocked(app.processName, app.uid, app);}if (mHeavyWeightProcess == app) {mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,mHeavyWeightProcess.userId, 0));mHeavyWeightProcess = null;}} else if (!app.removed) {// This app is persistent, so we need to keep its record around.// If it is not already on the pending app list, add it there// and start a new process for it.//该app是persistent的,需要对其进行重启,并把它添加到正在启动的列表中,并//设置restart=trueif (mPersistentStartingProcesses.indexOf(app) < 0) {mPersistentStartingProcesses.add(app);restart = true;}}....//经过上面的过滤,会调用这个分支条件重启persistent为true的appif (restart && !app.isolated) {// We have components that still need to be running in the// process, so re-launch it.if (index < 0) {ProcessList.remove(app.pid);}addProcessNameLocked(app);startProcessLocked(app, "restart", app.processName);return true;} else if (app.pid > 0 && app.pid != MY_PID) {// Goodbye!boolean removed;synchronized (mPidsSelfLocked) {mPidsSelfLocked.remove(app.pid);mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);}mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);if (app.isolated) {mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);}app.setPid(0);}return false;}

Android关键字persistent相关推荐

  1. Android 系统(88)---Android关键字persistent

    Android关键字persistent 在Android程序开发时我们会接触到一些系统为了某些功能而定义的关键属性,例如在AndroidManifest.xml文件中 经常看到的persistent ...

  2. android bugreport关键字

    aosp关于read bugreport的文档:https://source.android.com/setup/contribute/read-bug-reports,建议详细阅读. 跟踪CPU i ...

  3. Android ANR日志分析进行曲

    定义 ANR(Application Not Responding) 应用程序无响应.如果你应用程序在UI线程被阻塞太长时间,就会出现ANR,通常出现ANR,系统会弹出一个提示提示框,让用户知道,该程 ...

  4. Android开机时间分析

    一. 关于本篇博文 该文档简单主要描述了如何找出开机各个阶段耗时情况,以及对开机各个阶段的分析方法和如何优化开机时间,减少耗时.便于读者可以通过此文档了解开机时间的各个阶段的耗时情况. 二.开机各阶段 ...

  5. 最实用的Android Debug Bridge (ADB)使用手册

    文章目录 第1节 最常用案例 1.1 启动应用主界面 1.2 获取当前显示Activity 1.3 获取屏幕分辨率 1.4 获取App 冷热启动时间 1.5 清除App缓存 第2节 应用安装 2.1 ...

  6. Android BugReport异常快速排查手册

    快速排查 应用发生崩溃,如果是生产环境,通常容易找到,如果不是,那就麻烦很多.bug的发生总是那么突如其来,有时候让我们措手不及,现在我就来理一理如何淡定的解决bug: 应用异常退出有两种可能,一种是 ...

  7. travis-ci如何配置android

    travis-ci如何配置android travis-ci 关于android部分:http://docs.travis-ci.com/user/languages/android/ languag ...

  8. 【Android 逆向】Android 权限 ( 查看内存信息 | 查看 CPU 信息 | 查看电池信息 | 查看账户信息 | 查看 Activity 信息 | 查看 Package 信息 )

    文章目录 一.查看内存信息 二.查看 CPU 信息 三.查看电池信息 四.查看账户信息 五.查看 Activity 信息 六.查看 Package 信息 一.查看内存信息 查看系统内存详细信息 : 使 ...

  9. 【Android】 Intent应用详解

    转载:http://blog.csdn.net/liuhe688/article/details/7162988 看似尋常最奇崛,成如容易卻艱辛.北宋.王安石 看似普通的事情其实最不同寻常,并不是简简 ...

  10. configure 查找依赖库_Rust在编译Android的库时,如何设定依赖的第三方库引用的C/C++的动态库的搜索路径?...

    谢邀.不懂android,也不懂OpenCL.但是我尝试了解了一下你的问题. 既然你用了第三方库,那就得查源码了.翻开ocl 库的源码搜android关键字,很容易定位到下面代码. #https:// ...

最新文章

  1. RUP within the context of the Six Best Practices
  2. python b64 图片处理
  3. 无缓冲channel
  4. 构建现代Web应用时究竟是选择传统web应用还是SPA
  5. Java在ACM中的应用
  6. c语言sort函数_C语言经典面试题目及答案详解(二)
  7. Mysql基础知识:创建、查看、修改和删除表
  8. DN服务器修改配置文件,LDIF修改LDAP记录或配置示例
  9. cocos2D中scheduleOnce的陷阱
  10. 蓝桥杯 ADV-96 算法提高 复数求和
  11. linux 递归查看文件个数,Linux下递归读取文件数量
  12. 鸿蒙系统适配机型_余承东:华为手机鸿蒙系统体验比安卓更好,主流应用已完成适配...
  13. 软件测试与发布,软件测试与发布技术
  14. yii 获取当前域名_yii2 在域名后面加一个路径作为首页
  15. 又一打包工具介绍:Installshield 打包安装包心得
  16. Linux rpm命令
  17. android怎么安装CA证书及代理抓包
  18. 将Tomcat注册成系统服务,并且设置成系统自启动项
  19. 前端下载文件流PDF文件显示空白 或 无法打开
  20. HDOJ 1164 Eddy's research I(拆分成素数因子)

热门文章

  1. 这些竟然是身体的求救信号!你看懂了吗?
  2. 2019java面试(二)
  3. 我的Unity3d学习总结
  4. 7714天,王小川正式卸任搜狗CEO!网友:别了。。。
  5. 计算机用户guest无法删除吗,Win7怎么删除Guest账户?
  6. 墨尔本大学计算机科学要求,墨尔本大学计算机科学
  7. chromecast投屏_利用谷歌Chromecast,3个简单的步骤教你将手机投屏到电视上
  8. 计算机二级是专业技术职务吗,计算机二级算中级技能证吗
  9. Win10下载和安装FPGA软件:Quartus Prime( Standard 版本18.1)
  10. CMOS图像传感器工作原理