Android关键字persistent详细分析

目录
  • Android关键字persistent原理分析​
    • persistent属性作用
    • 使用
  • 二、原理分析
    • 1、persistent属性的解析
    • 2、系统启动时启动persistent为true的app
    • 3、app被异常结束后系统重新启动persistent为true的app
  • 总结

Android关键字persistent原理分析​

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

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

persistent属性作用

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

<attr name="persistent" format="boolean" />

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

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

使用

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 apps

  startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

  // Start up initial activity.

  mBooting = true;

  // Enable home activity for system user, so that the system can always boot

  if (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方法。

该方法会遍历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 = null

 if (!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被设置为false

  AppGlobals.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);

  //启动该app

  startProcessLocked(app, "added application", app.processName, abiOverride,

   null /* entryPoint */, null /* entryPointArgs */);

 }

 return app;

 }

}

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

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=true

  if (mPersistentStartingProcesses.indexOf(app) < 0) {

  mPersistentStartingProcesses.add(app);

  restart = true;

  }

 }

....

//经过上面的过滤,会调用这个分支条件重启persistent为true的app

 if (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;

}

总结

  1. persistent的声明在AndroidManifest.xml中的 t属性,默认值为false
  2. persistent的声明,必须该app是系统内置应用,并且在AndroidManifest.xml中的声明android:persisten = “true”,才能生效
  3. persistent的声明为true的内置app被异常杀死的时候,系统会将其拉起重启启动

以上就是Android关键字persistent详细分析的详细内容,更多关于Android关键字persistent的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android中persistent属性用法详解

    本文实例讲述了Android中persistent属性用法.分享给大家供大家参考,具体如下: 前段时间在研究telephony时,一直没有在framework下发现对telephony的初始化(PhoneFactory.Java中的makeDefaultPhones函数)的调用.结果全局搜索之后发现在application PhoneApp(packages/apps/Phone)中调用了.但是application PhoneApp既没有被Broadcast唤醒,也没有被其他service调用

  • Android关键字persistent详细分析

    目录 Android关键字persistent原理分析​ persistent属性作用 使用 二.原理分析 1.persistent属性的解析 2.系统启动时启动persistent为true的app 3.app被异常结束后系统重新启动persistent为true的app 总结 Android关键字persistent原理分析​ 在Android程序开发时我们会接触到一些系统为了某些功能而定义的关键属性,例如在AndroidManifest.xml文件中 经常看到的persistent.pro

  • Android编程之微信SDK分享功能过程步骤详细分析

    本文实例讲述了Android编程之微信SDK分享功能过程步骤详细分析.分享给大家供大家参考,具体如下: 之前已经分析过怎么用官方的demo分享微信信息了,在这里我就不再多说,其中关于在自己应用分享说得很简单,本文作者也是经过一番折腾才弄成功,为了以后让大家都少走弯路,决定在这里从头到尾介绍怎么在自己的应用中分享功能 注意:顺序不能乱!! 1.建立自己的应用 TestShareWX (1)应用包名是com.freeson.test,然后建立一个测试Activity,名字为TestActivity,

  • 详细分析Android中onTouch事件传递机制

    onTach介绍 ontach是Android系统中整个事件机制的基础.Android中的其他事件,如onClick.onLongClick等都是以onTach为基础的. onTach包括从手指按下到离开手机屏幕的整个过程,在微观形式上,具体表现为action_down.action_move和action_up等过程. onTach两种主要定义形式如下: 1.在自定义控件中,常见的有重写onTouchEvent(MotionEvent ev)方法.如在开发中经常可以看到重写的onTouchEv

  • 详细分析java并发之volatile关键字

    Java面试中经常会涉及关于volatile的问题.本文梳理下volatile关键知识点. volatile字意为"易失性",在Java中用做修饰对象变量.它不是Java特有,在C,C++,C#等编程语言也存在,只是在其它编程语言中使用有所差异,但总体语义一致.比如使用volatile 能阻止编译器对变量的读写优化.简单说,如果一个变量被修饰为volatile,相当于告诉系统说我容易变化,编译器你不要随便优化(重排序,缓存)我. Happens-before 规范上,Java内存模型遵

  • C语言详细分析讲解关键字enum与sizeof及typedef的用法

    目录 一.枚举类型的使用方法 二.sizeof 关键字的用法 三.typedef 的意义 四.小结 一.枚举类型的使用方法 enum 是 C 语言中的一种自定义类型 enum 值是可以根据需要自定义的整型值 第一个定义的 enum 值默认为 0 默认情况下的 enum 值是在前一个定义值的基础上加 1 enum 类型的变量只能取定义时的离散值 enum 中定义的值是C语言中真正意义上的常量 在工程中 enum 多用于定义整型常量 下面看一段 enum 的使用代码吧: #include<stdio

  • C语言详细分析讲解关键字const与volatile的用法

    目录 一.const 只读变量 二.const 全局变量的分歧 三.const 的本质 四.const 修饰函数参数和返回值 五.volatile 解析 六.小结 一.const 只读变量 const 修饰的变量是只读的,本质还是变量 const 修饰的局部变量在栈上分配空间 const 修饰的全局变量在全局数据区分配空间 const 只在编译期有用,在运行期无用 const 修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边. 二.const 全局变量的分歧 在现代C语言编

  • C语言详细分析讲解关键字goto与void的作用

    目录 一.关于goto 二.void 的意义 三.小结 一.关于goto 高手潜规则:禁用 goto 项目经验:程序质量与 goto 的出现次数成反比 最后的判决:将 goto 打入冷宫 下面看一段 goto 副作用分析的代码: #include <stdio.h> #include <malloc.h> void func(int n) { int* p = NULL; if( n < 0 ) { goto STATUS; } p = (int*)malloc(sizeof

  • Java超详细分析讲解final关键字的用法

    目录 基本介绍 final细节01 final细节02 基本介绍 final 可以修饰类.属性.方法和局部变量. 在某些情况下,程序员可能有以下需求,就会使用到final: Base Sub 类 1)当不希望类被继承时,可以用final修饰. 2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字 修饰.[案例演示:访问修饰符 final 返回类型方法名] 3)当不希望类的的某个属性的值被修改,可以用final修饰.[案例演示: public final dou

  • Android Choreographer源码详细分析

    目录 一.首先介绍一些基础知识 二.android源码中Choreographer是如何运行 一.首先介绍一些基础知识 1.刷新率(Refresh Rate): 刷新率代表屏幕在一秒内刷新屏幕的次数,用赫兹来表示.赫兹是频率的单位,一秒震动的次数.这个刷新率取决于硬件固定的参数.这个值一般是60Hz.即每16.66ms刷新一次屏幕. 2.帧速率(Frame Rate): 帧速率代表了GPU在一秒内绘制操作的帧数.比如30FPS.60FPS.Frame Per Second. 3.如果两个设备独立

  • Android用于加载xml的LayoutInflater源码超详细分析

    1.在view的加载和绘制流程中:文章链接 我们知道,定义在layout.xml布局中的view是通过LayoutInflate加载并解析成Java中对应的View对象的.那么具体的解析过程是哪样的. 先看onCreate方法,如果我们的Activity是继承自AppCompactActivity.android是通过getDelegate返回的对象setContentView,这个mDelegate 是AppCompatDelegateImpl的实例. @Override protected

随机推荐