Android系统级保活方案

一、防止应用在系统低内存的时候被回收

代码路径:./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;

    ...
}

 二、android:persistent="true"

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应用随系统启动,启动时机很早,早于开机广播的发送,以及桌面的启动。

 

你可能感兴趣的:(Android系统级保活方案)