一、防止应用在系统低内存的时候被回收
代码路径:./frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
static final String mThirdPartyAppWhite = "com.android.packagename";
private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
ProcessRecord TOP_APP, boolean doingAll, boolean
reportingProcessState, long now) {
boolean success = true;
if (app.curRawAdj != app.setRawAdj) {
if (wasKeeping && !app.keeping) {
// This app is no longer something we want to keep. Note
// its current wake lock time to later know to kill it if
// it is not behaving well.
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
app.pid, SystemClock.elapsedRealtime());
}
app.lastCpuTime = app.curCpuTime;
}
app.setRawAdj = app.curRawAdj;
}
//add to writelist begin
if (mThirdPartyAppWhite.equals(app.processName)) {
app.curAdj = ProcessList.FOREGROUND_APP_ADJ;
}
//add to writelist end
if (app.curAdj != app.setAdj) {
if (Process.setOomAdj(app.pid, app.curAdj)) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set " + app.pid + " " + app.processName +
" adj " + app.curAdj + ": " + app.adjType);
app.setAdj = app.curAdj
} else {
success = false;
Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
}
}
...
}
原理:内存低的时候系统会杀死adj在9到15的进程,setOomAdj是设置进程的adj,我们在setOomAdj之前把我们要放入白名单的进程的adj设置为0,当然,还可以设为其他的值,参考ProcessList.java。
关于oom_adj:进程是有它的优先级的,这个优先级通过进程的adj值来反映,它是linux内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收,adj值定义在com.android.server.am.ProcessList类中,这个类路径是./frameworks/base/services/java/com/android/server/am/ProcessList.java。oom_adj的值越小,进程的优先级越高,普通进程oom_adj值是大于等于0的,而系统进程oom_adj的值是小于0的,我们可以通过cat /proc/进程id/oom_adj可以看到当前进程的adj值。也就是说,oom_adj越大,占用物理内存越多会被最先kill掉。
/**
* Activity manager code dealing with processes.
*/
final class ProcessList {
// The minimum time we allow between crashes, for us to consider this
// application to be bad and stop and its services and reject broadcasts.
static final int MIN_CRASH_INTERVAL = 60*1000;
// OOM adjustments for processes in various states:
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
static final int UNKNOWN_ADJ = 16;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 15;
static final int CACHED_APP_MIN_ADJ = 9;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 8;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app. This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 7;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 6;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 5;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 4;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 2;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -12;
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -17;
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
// The minimum number of cached apps we want to be able to keep around,
// without empty apps being able to push them out of memory.
static final int MIN_CACHED_APPS = 2;
// The maximum number of cached processes we will keep around before killing them.
// NOTE: this constant is *only* a control to not let us go too crazy with
// keeping around processes on devices with large amounts of RAM. For devices that
// are tighter on RAM, the out of memory killer is responsible for killing background
// processes as RAM is needed, and we should *never* be relying on this limit to
// kill them. Also note that this limit only applies to cached background processes;
// we have no limit on the number of service, visible, foreground, or other such
// processes and the number of those processes does not count against the cached
// process limit.
static final int MAX_CACHED_APPS = 24;
// We allow empty processes to stick around for at most 30 minutes.
static final long MAX_EMPTY_TIME = 30*60*1000;
// The maximum number of empty app processes we will let sit around.
private static final int MAX_EMPTY_APPS = computeEmptyProcessLimit(MAX_CACHED_APPS);
// The number of empty apps at which we don't consider it necessary to do
// memory trimming.
static final int TRIM_EMPTY_APPS = MAX_EMPTY_APPS/2;
// The number of cached at which we don't consider it necessary to do
// memory trimming.
static final int TRIM_CACHED_APPS = ((MAX_CACHED_APPS-MAX_EMPTY_APPS)*2)/3;
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_LOW_THRESHOLD = 5;
...
}
1.下面通过两个方法来看一下添加了该属性的应用是如何被选中的。
代码路径:./frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback) {
...
synchronized (this) {
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
List apps = AppGlobals.getPackageManager().
getPersistentApplications(STOCK_PM_FLAGS);
if (apps != null) {
int N = apps.size();
int i;
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.
}
...
}
}
}
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
代码路径:./frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
public List getPersistentApplications(int flags) {
final ArrayList finalList = new ArrayList();
// reader
synchronized (mPackages) {
final Iterator i = mPackages.values().iterator();
final int userId = UserHandle.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);
if (ps != null) {
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
finalList.add(ai);
}
}
}
}
}
return finalList;
}
从代码里可以看出,带persistent标志的系统应用是一定会被选上的,但如果不是系统应用的话,则要进一步判断当前是否处于“安全模式”,一旦处于安全模式,那么就算应用设置了persistent属性,也不会被选中。
2.添加该属性的应用是如何保活的
为了保证这种持久性,persistent应用必须能够在异常出现时,自动重新启动。在Android里是这样实现的:每个ActivityThread中会有一个专门和AMS通信的binder实体——final ApplicationThread mAppThread。这个实体在AMS中对应的代理接口为IApplicationThread。当AMS执行到attachApplicationLocked()时,会针对目标用户进程的IApplicationThread接口,注册一个binder讣告监听器,一旦日后用户进程意外挂掉,AMS就能在第一时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应用是persistent的,它会尝试重新启动这个应用。
3.可能发生的问题
目前来看由于这个应用是一直存活的所以在他自升级,清除数据等过程中,应用也不会退出,这就导致应用即使清除数据,但是仍然缓存有数据导致运行异常。代码如下:
if (app.persistent && !evenPersistent) {
// we don't kill persistent processes
if (IS_ENG_BUILD || DEBUG_PROCESSES) {
Slog.d(TAG, "ACT-killPackageProcessesLocked ignore persistent process " +
app.persistent + " " + evenPersistent);
}
continue;
}
但是android P开始限制了persistent应用升级,报错信息如下:
[INSTALL_FAILED_INVALID_APK: Package xxx is a persistent app. Persistent apps are not updateable.]
4.从上面的介绍可知,persistent应用随系统启动,启动时机很早,早于开机广播的发送,以及桌面的启动。