第一部分:进程OomAdj值的设置
这个流程中,ActivityManagerService会计算出进程的OomAdj值,然后通过Lmkd这个native进程来将OomAdj值分别写入对应进程的oom_score_adj节点去。可以通过cat /proc/%pid/oom_score_adj来查看每个进程的OomAdj值。
注意:
①OomAdj值越小表示优先级越高,越不容易被kill。
②ActivityManagerService中为进程设定的OomAdj值取值范围为-16~16,设定到oom_score_adj节点中的值是经过 OomAdj*1000/17 公式计算出来的。
③native进程OomAdj值默认为-17,也就是说native进程oom_score_adj节点中值必是-1000.
第二部分:核心调用lowmem_shrink()
这个函数主要根据当前剩余内存与lowmem_minfree来评判当前内存已经达到哪个阀值以下(每个阀值都对应一个lowmem_adj值),进而得出一个lowmem_adj基准值(只有OomAdj值大于这个lowmem_adj基准值的进程才可能被杀)。
代码在/drivers/staging/android/lowmemorykiller.c
- static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
- {
- struct task_struct *tsk;
- struct task_struct *selected = NULL;
- int rem = 0;
- int tasksize;
- int i;
- int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
- int selected_tasksize = 0;
- int selected_oom_score_adj;
- int array_size = ARRAY_SIZE(lowmem_adj);
- int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
- int other_file = global_page_state(NR_FILE_PAGES) -
- global_page_state(NR_SHMEM);
- if (lowmem_adj_size < array_size)
- array_size = lowmem_adj_size;
- if (lowmem_minfree_size < array_size)
- array_size = lowmem_minfree_size;
- for (i = 0; i < array_size; i++) { //根据当前内存与lowmem_minfree数组进行评判,找到lowmem_adj基准值赋给min_score_adj;
- if (other_free < lowmem_minfree[i] &&
- other_file < lowmem_minfree[i]) {
- min_score_adj = lowmem_adj[i];
- break;
- }
- }
- if (sc->nr_to_scan > 0)
- lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n",
- sc->nr_to_scan, sc->gfp_mask, other_free,
- other_file, min_score_adj);
- rem = global_page_state(NR_ACTIVE_ANON) +
- global_page_state(NR_ACTIVE_FILE) +
- global_page_state(NR_INACTIVE_ANON) +
- global_page_state(NR_INACTIVE_FILE);
- if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
- lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
- sc->nr_to_scan, sc->gfp_mask, rem);
- return rem;
- }
- selected_oom_score_adj = min_score_adj;
- rcu_read_lock();
- for_each_process(tsk) { //该for循环找出oom_score_adj值最大的进程作为目标进程(将被kill),如果最大oom_score_adj值有多个进程,那么选取rss值最大的进程为目标进程;
- struct task_struct *p;
- int oom_score_adj;
- if (tsk->flags & PF_KTHREAD)
- continue;
- p = find_lock_task_mm(tsk);
- if (!p)
- continue;
- if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
- time_before_eq(jiffies, lowmem_deathpending_timeout)) {
- task_unlock(p);
- rcu_read_unlock();
- return 0;
- }
- oom_score_adj = p->signal->oom_score_adj;
- if (oom_score_adj < min_score_adj) {
- task_unlock(p);
- continue;
- }
- tasksize = get_mm_rss(p->mm);
- task_unlock(p);
- if (tasksize <= 0)
- continue;
- if (selected) {
- if (oom_score_adj < selected_oom_score_adj)
- continue;
- if (oom_score_adj == selected_oom_score_adj &&
- tasksize <= selected_tasksize)
- continue;
- }
- selected = p;
- selected_tasksize = tasksize;
- selected_oom_score_adj = oom_score_adj;
- lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
- p->pid, p->comm, oom_score_adj, tasksize);
- }
- if (selected) { //前面for循环找到一个目标进程,那么便调用send_sig()干掉它。
- lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
- selected->pid, selected->comm,
- selected_oom_score_adj, selected_tasksize);
- lowmem_deathpending_timeout = jiffies + HZ;
- send_sig(SIGKILL, selected, 0);
- set_tsk_thread_flag(selected, TIF_MEMDIE);
- rem -= selected_tasksize;
- }
- lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
- sc->nr_to_scan, sc->gfp_mask, rem);
- rcu_read_unlock();
- return rem;
- }
注意:由于native进程的Oomadj值为-17,SystemServer进程的Oomadj值为-16,毫无疑问native进程不会被Lowmemorykiller干掉。
第三部分:Oomadj的计算
OomAdj的计算主要在computeOomAdjLocked()函数中完成。
- private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
- boolean doingAll, long now) {
- if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed.
- return app.curRawAdj;
- }
- if (app.thread == null) {
- app.adjSeq = mAdjSeq;
- app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
- }
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
- app.adjSource = null;
- app.adjTarget = null;
- app.empty = false;
- app.cached = false;
- final int activitiesSize = app.activities.size();
- if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) { //如果是常驻进程、SystemServer进程,那么该条件是满足的,对于一般进程maxAdj值为UNKNOWN_ADJ
- // The max adjustment doesn't allow this app to be anything
- // below foreground, so it is not worth doing work for it.
- app.adjType = "fixed";
- app.adjSeq = mAdjSeq;
- app.curRawAdj = app.maxAdj;
- app.foregroundActivities = false;
- app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
- app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
- // System processes can do UI, and when they do we want to have
- // them trim their memory after the user leaves the UI. To
- // facilitate this, here we need to determine whether or not it
- // is currently showing UI.
- app.systemNoUi = true;
- if (app == TOP_APP) {
- app.systemNoUi = false;
- } else if (activitiesSize > 0) {
- for (int j = 0; j < activitiesSize; j++) {
- final ActivityRecord r = app.activities.get(j);
- if (r.visible) {
- app.systemNoUi = false;
- }
- }
- }
- if (!app.systemNoUi) { //如果进程是当前resume activity的进程,或者有可见的activity,那么把curProcState修改成PROCESS_STATE_PERSISTENT_UI
- app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
- }
- return (app.curAdj=app.maxAdj);
- }
- app.systemNoUi = false; /*以下逻辑是计算普通进程的Oomadj值,主要计算进程的adj、schedGroup、procState、foregroundActivities四个变量*/
- // Determine the importance of the process, starting with most
- // important to least, and assign an appropriate OOM adjustment.
- int adj;
- int schedGroup;
- int procState;
- boolean foregroundActivities = false;
- BroadcastQueue queue;
- if (app == TOP_APP) { //这大段if else逻辑里面的条件是权重最高的,如果满足这些条件之一,那么几个状态值基本就确定下来了,如果都不满足,那么最后一个else会给一个初值;
- // The last app on the list is the foreground app.
- adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "top-activity";
- foregroundActivities = true;
- procState = ActivityManager.PROCESS_STATE_TOP;
- } else if (app.instrumentationClass != null) {
- // Don't want to kill running instrumentation.
- adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "instrumentation";
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- } else if ((queue = isReceivingBroadcast(app)) != null) {
- // An app that is currently receiving a broadcast also
- // counts as being in the foreground for OOM killer purposes.
- // It's placed in a sched group based on the nature of the
- // broadcast as reflected by which queue it's active in.
- adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = (queue == mFgBroadcastQueue)
- ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.adjType = "broadcast";
- procState = ActivityManager.PROCESS_STATE_RECEIVER;
- } else if (app.executingServices.size() > 0) {
- // An app that is currently executing a service callback also
- // counts as being in the foreground.
- adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = app.execServicesFg ?
- Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.adjType = "exec-service";
- procState = ActivityManager.PROCESS_STATE_SERVICE;
- //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
- } else {
- // As far as we know the process is empty. We may change our mind later.
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- // At this point we don't actually know the adjustment. Use the cached adj
- // value that the caller wants us to.
- adj = cachedAdj; //cachedAdj值为进程的上一次计算出来的Oomadj值或UNKNOWN_ADJ,我们把它假设成UNKNOWN_ADJ好了。
- procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- app.cached = true;
- app.empty = true;
- app.adjType = "cch-empty";
- }
- // Examine all activities if not already foreground.
- if (!foregroundActivities && activitiesSize > 0) { //这段逻辑主要遍历进程中的所有activity,根据这些activity的状态来更新adj、procState等值;
- for (int j = 0; j < activitiesSize; j++) {
- final ActivityRecord r = app.activities.get(j);
- if (r.app != app) {
- Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
- + app + "?!?");
- continue;
- }
- if (r.visible) {
- // App has a visible activity; only upgrade adjustment.
- if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- app.adjType = "visible";
- }
- if (procState > ActivityManager.PROCESS_STATE_TOP) {
- procState = ActivityManager.PROCESS_STATE_TOP;
- }
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- break;
- } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "pausing";
- }
- if (procState > ActivityManager.PROCESS_STATE_TOP) {
- procState = ActivityManager.PROCESS_STATE_TOP;
- }
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- } else if (r.state == ActivityState.STOPPING) {
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "stopping";
- }
- // For the process state, we will at this point consider the
- // process to be cached. It will be cached either as an activity
- // or empty depending on whether the activity is finishing. We do
- // this so that we can treat the process as cached for purposes of
- // memory trimming (determing current memory level, trim command to
- // send to process) since there can be an arbitrary number of stopping
- // processes and they should soon all go into the cached state.
- if (!r.finishing) {
- if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
- }
- }
- app.cached = false;
- app.empty = false;
- foregroundActivities = true;
- } else {
- if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
- app.adjType = "cch-act";
- }
- }
- }
- }
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { //根据进程是否有前台后台service来更新adj、procState等值,当然如果以前算出来的adj<=PERCEPTIBLE_APP_ADJ,那就没必要考虑前台后台service了;
- if (app.foregroundServices) {
- // The user is aware of this app, so make it visible.
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- app.cached = false;
- app.adjType = "fg-service";
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- } else if (app.forcingToForeground != null) {
- // The user is aware of this app, so make it visible.
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- app.cached = false;
- app.adjType = "force-fg";
- app.adjSource = app.forcingToForeground;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- }
- if (app == mHeavyWeightProcess) { //判断进程是否mHeavyWeightProcess进程
- if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- // We don't want to kill the current heavy-weight process.
- adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.cached = false;
- app.adjType = "heavy";
- }
- if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
- procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
- }
- }
- if (app == mHomeProcess) { //判断是否launcher进程;
- if (adj > ProcessList.HOME_APP_ADJ) {
- // This process is hosting what we currently consider to be the
- // home app, so we don't want to let it go into the background.
- adj = ProcessList.HOME_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.cached = false;
- app.adjType = "home";
- }
- if (procState > ActivityManager.PROCESS_STATE_HOME) {
- procState = ActivityManager.PROCESS_STATE_HOME;
- }
- }
- if (app == mPreviousProcess && app.activities.size() > 0) {<span style="white-space:pre"> </span>//mPreviousProcess代表last Stoped activity所在的进程
- if (adj > ProcessList.PREVIOUS_APP_ADJ) {
- // This was the previous process that showed UI to the user.
- // We want to try to keep it around more aggressively, to give
- // a good experience around switching between two apps.
- adj = ProcessList.PREVIOUS_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.cached = false;
- app.adjType = "previous";
- }
- if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
- }
- }
- <span style="white-space:pre"> </span>/*至此已经初步设置了Oomadj值,下面的逻辑就是根据service、provider来微调<span style="font-family: Arial, Helvetica, sans-serif;">Oomadj值</span>*/
- if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
- + " reason=" + app.adjType);
- // By default, we use the computed adjustment. It may be changed if
- // there are applications dependent on our services or providers, but
- // this gives us a baseline and makes sure we don't get into an
- // infinite recursion.
- app.adjSeq = mAdjSeq;
- app.curRawAdj = adj;
- app.hasStartedServices = false;
- if (mBackupTarget != null && app == mBackupTarget.app) {<span style="white-space:pre"> </span>//判断进程是否正在备份
- // If possible we want to avoid killing apps while they're being backed up
- if (adj > ProcessList.BACKUP_APP_ADJ) {
- if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
- adj = ProcessList.BACKUP_APP_ADJ;
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
- }
- app.adjType = "backup";
- app.cached = false;
- }
- if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
- procState = ActivityManager.PROCESS_STATE_BACKUP;
- }
- }
- boolean mayBeTop = false;
- for (int is = app.services.size()-1;
- is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
- || procState > ActivityManager.PROCESS_STATE_TOP);
- is--) {
- ServiceRecord s = app.services.valueAt(is);
- if (s.startRequested) {<span style="white-space:pre"> </span>//<span style="font-family: Arial, Helvetica, sans-serif;">startRequested=true表示service已经启动了,没有被stop;</span>
- app.hasStartedServices = true;
- if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
- procState = ActivityManager.PROCESS_STATE_SERVICE;
- }
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-ui-services";
- }
- } else {
- if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has seen some activity within
- // recent memory, so we will keep its process ahead
- // of the background processes.
- if (adj > ProcessList.SERVICE_ADJ) {
- adj = ProcessList.SERVICE_ADJ;
- app.adjType = "started-services";
- app.cached = false;
- }
- }
- // If we have let the service slide into the background
- // state, still have some text describing what it is doing
- // even though the service no longer has an impact.
- if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-services";
- }
- }
- }
- for (int conni = s.connections.size()-1;
- conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
- || procState > ActivityManager.PROCESS_STATE_TOP);
- conni--) {
- ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
- for (int i = 0;
- i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
- || procState > ActivityManager.PROCESS_STATE_TOP);
- i++) {
- // XXX should compute this based on the max of
- // all connected clients.
- ConnectionRecord cr = clist.get(i);
- if (cr.binding.client == app) {
- // Binding to ourself is not interesting.
- continue;
- }
- if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
- ProcessRecord client = cr.binding.client;
- int clientAdj = computeOomAdjLocked(client, cachedAdj,
- TOP_APP, doingAll, now);
- int clientProcState = client.curProcState;
- if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty. The specific cached state
- // doesn't propagate except under certain conditions.
- clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- }
- String adjType = null;
- if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
- // Not doing bind OOM management, so treat
- // this guy more like a started service.
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-ui-services";
- }
- app.cached = false;
- clientAdj = adj;
- clientProcState = procState;
- } else {
- if (now >= (s.lastActivity
- + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has not seen activity within
- // recent memory, so allow it to drop to the
- // LRU list if there is no other reason to keep
- // it around. We'll also tag it with a label just
- // to help debug and undertand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-services";
- }
- clientAdj = adj;
- }
- }
- }
- if (adj > clientAdj) {
- // If this process has recently shown UI, and
- // the process that is binding to it is less
- // important than being visible, then we don't
- // care about the binding as much as we care
- // about letting this process get into the LRU
- // list to be killed and restarted if needed for
- // memory.
- if (app.hasShownUi && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-bound-ui-services";
- } else {
- if ((cr.flags&(Context.BIND_ABOVE_CLIENT
- |Context.BIND_IMPORTANT)) != 0) {
- adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
- ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
- } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
- && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
- && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
- adj = clientAdj;
- } else {
- if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- if (!client.cached) {
- app.cached = false;
- }
- adjType = "service";
- }
- }
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
- if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
- // Special handling of clients who are in the top state.
- // We *may* want to consider this process to be in the
- // top state as well, but only if there is not another
- // reason for it to be running. Being on the top is a
- // special state, meaning you are specifically running
- // for the current top app. If the process is already
- // running in the background for some other reason, it
- // is more important to continue considering it to be
- // in the background state.
- mayBeTop = true;
- clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- } else {
- // Special handling for above-top states (persistent
- // processes). These should not bring the current process
- // into the top state, since they are not on top. Instead
- // give them the best state after that.
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- }
- }
- } else {
- if (clientProcState <
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
- }
- }
- if (procState > clientProcState) {
- procState = clientProcState;
- }
- if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
- app.pendingUiClean = true;
- }
- if (adjType != null) {
- app.adjType = adjType;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = cr.binding.client;
- app.adjSourceProcState = clientProcState;
- app.adjTarget = s.name;
- }
- }
- if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
- app.treatLikeActivity = true;
- }
- final ActivityRecord a = cr.activity;
- if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = ProcessList.FOREGROUND_APP_ADJ;
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- app.cached = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjSourceProcState = procState;
- app.adjTarget = s.name;
- }
- }
- }
- }
- }
- for (int provi = app.pubProviders.size()-1;
- provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
- || procState > ActivityManager.PROCESS_STATE_TOP);
- provi--) {
- ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
- for (int i = cpr.connections.size()-1;
- i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
- || procState > ActivityManager.PROCESS_STATE_TOP);
- i--) {
- ContentProviderConnection conn = cpr.connections.get(i);
- ProcessRecord client = conn.client;
- if (client == app) {
- // Being our own client is not interesting.
- continue;
- }
- int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
- int clientProcState = client.curProcState;
- if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty.
- clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- }
- if (adj > clientAdj) {
- if (app.hasShownUi && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- app.adjType = "cch-ui-provider";
- } else {
- adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
- ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
- app.adjType = "provider";
- }
- app.cached &= client.cached;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE;
- app.adjSource = client;
- app.adjSourceProcState = clientProcState;
- app.adjTarget = cpr.name;
- }
- if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
- if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
- // Special handling of clients who are in the top state.
- // We *may* want to consider this process to be in the
- // top state as well, but only if there is not another
- // reason for it to be running. Being on the top is a
- // special state, meaning you are specifically running
- // for the current top app. If the process is already
- // running in the background for some other reason, it
- // is more important to continue considering it to be
- // in the background state.
- mayBeTop = true;
- clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- } else {
- // Special handling for above-top states (persistent
- // processes). These should not bring the current process
- // into the top state, since they are not on top. Instead
- // give them the best state after that.
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- }
- }
- if (procState > clientProcState) {
- procState = clientProcState;
- }
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- }
- // If the provider has external (non-framework) process
- // dependencies, ensure that its adjustment is at least
- // FOREGROUND_APP_ADJ.
- if (cpr.hasExternalProcessHandles()) {
- if (adj > ProcessList.FOREGROUND_APP_ADJ) {
- adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.cached = false;
- app.adjType = "provider";
- app.adjTarget = cpr.name;
- }
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- }
- }
- }
- if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
- // A client of one of our services or providers is in the top state. We
- // *may* want to be in the top state, but not if we are already running in
- // the background for some other reason. For the decision here, we are going
- // to pick out a few specific states that we want to remain in when a client
- // is top (states that tend to be longer-term) and otherwise allow it to go
- // to the top state.
- switch (procState) {
- case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- case ActivityManager.PROCESS_STATE_SERVICE:
- // These all are longer-term states, so pull them up to the top
- // of the background states, but not all the way to the top state.
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- break;
- default:
- // Otherwise, top is a better choice, so take it.
- procState = ActivityManager.PROCESS_STATE_TOP;
- break;
- }
- }
- if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- if (app.hasClientActivities) {
- // This is a cached process, but with client activities. Mark it so.
- procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
- app.adjType = "cch-client-act";
- } else if (app.treatLikeActivity) {
- // This is a cached process, but somebody wants us to treat it like it has
- // an activity, okay!
- procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
- app.adjType = "cch-as-act";
- }
- }
- if (adj == ProcessList.SERVICE_ADJ) {
- if (doingAll) {
- app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
- mNewNumServiceProcs++;
- //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
- if (!app.serviceb) {
- // This service isn't far enough down on the LRU list to
- // normally be a B service, but if we are low on RAM and it
- // is large we want to force it down since we would prefer to
- // keep launcher over it.
- if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
- && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
- app.serviceHighRam = true;
- app.serviceb = true;
- //Slog.i(TAG, "ADJ " + app + " high ram!");
- } else {
- mNewNumAServiceProcs++;
- //Slog.i(TAG, "ADJ " + app + " not high ram!");
- }
- } else {
- app.serviceHighRam = false;
- }
- }
- if (app.serviceb) {
- adj = ProcessList.SERVICE_B_ADJ;
- }
- }
- app.curRawAdj = adj;
- //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
- // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
- if (adj > app.maxAdj) {
- adj = app.maxAdj;
- if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- }
- // Do final modification to adj. Everything we do between here and applying
- // the final setAdj must be done in this function, because we will also use
- // it when computing the final cached adj later. Note that we don't need to
- // worry about this for max adj above, since max adj will always be used to
- // keep it out of the cached vaues.
- app.curAdj = app.modifyRawOomAdj(adj);
- app.curSchedGroup = schedGroup;
- app.curProcState = procState;
- app.foregroundActivities = foregroundActivities;
- return app.curRawAdj;