美文网首页
Android 进程优先级和 LowMemoryKiller 机

Android 进程优先级和 LowMemoryKiller 机

作者: mao眼 | 来源:发表于2016-12-07 16:00 被阅读839次

    接上篇

    computeOomAdjLocked

    // ActivityManagerService.java
    
    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) {  // 前台:adj 0
                // 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) {
                    app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
                }
                return (app.curAdj=app.maxAdj);
            }
            app.systemNoUi = false;
            final int PROCESS_STATE_TOP = mTopProcessState;
            
            // 确定进程优先级,从高到低,分配一个合适的 OOM_ADJ
            // 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) { // 1. 前台应用
                // 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 = PROCESS_STATE_TOP;
            } else if (app.instrumentationClass != null) { // 2. instrumentation
                // Don't want to kill running instrumentation.
                adj = ProcessList.FOREGROUND_APP_ADJ;
                schedGroup = Process.THREAD_GROUP_DEFAULT;
                app.adjType = "instrumentation";
                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
            } else if ((queue = isReceivingBroadcast(app)) != null) { // 正在接收 Broadcast
                // 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) { // 正在执行 Service 回调
                // 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 { // 其他条件暂时认定empty,缓存
                // 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;
                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 进行判定
                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 + "?!? Using " + r.app + " instead.");
                        continue;
                    }
                    if (r.visible) {
                        // App has a visible activity; only upgrade adjustment.  
                        // Visible
                        if (adj > ProcessList.VISIBLE_APP_ADJ) {
                            adj = ProcessList.VISIBLE_APP_ADJ;
                            app.adjType = "visible";
                        }
                        if (procState > PROCESS_STATE_TOP) {
                            procState = 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 > PROCESS_STATE_TOP) {
                            procState = 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) {
                if (app.foregroundServices) {
                    // The user is aware of this app, so make it visible.
                    adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                    procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                    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) {
                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) {
                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) {
                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;
                }
            }
            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) {
                // 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_BACKUP, "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) {
                    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.
                                        if ((cr.flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
                                            clientProcState =
                                                    ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                        } else if (mWakefulness
                                                        == PowerManagerInternal.WAKEFULNESS_AWAKE &&
                                                (cr.flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
                                                        != 0) {
                                            clientProcState =
                                                    ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                        } else {
                                            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_BOUND_FOREGROUND_SERVICE;
                        }
                    }
                    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_BOUND_FOREGROUND_SERVICE;
                        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;
        }
    

    applyOomAdjLocked

    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
                long nowElapsed) {
            boolean success = true;
            if (app.curRawAdj != app.setRawAdj) {
                app.setRawAdj = app.curRawAdj;
            }
            int changes = 0;
            if (app.curAdj != app.setAdj) {
                ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                        "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
                        + app.adjType);
                app.setAdj = app.curAdj;
            }
            if (app.setSchedGroup != app.curSchedGroup) {
                app.setSchedGroup = app.curSchedGroup;
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                        "Setting process group of " + app.processName
                        + " to " + app.curSchedGroup);
                if (app.waitingToKill != null && app.curReceiver == null
                        && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
                    app.kill(app.waitingToKill, true);
                    success = false;
                } else {
                    if (true) {
                        long oldId = Binder.clearCallingIdentity();
                        try {
                            Process.setProcessGroup(app.pid, app.curSchedGroup);
                        } catch (Exception e) {
                            Slog.w(TAG, "Failed setting process group of " + app.pid
                                    + " to " + app.curSchedGroup);
                            e.printStackTrace();
                        } finally {
                            Binder.restoreCallingIdentity(oldId);
                        }
                    } else {
                        if (app.thread != null) {
                            try {
                                app.thread.setSchedulingGroup(app.curSchedGroup);
                            } catch (RemoteException e) {
                            }
                        }
                    }
                    Process.setSwappiness(app.pid,
                            app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE);
                }
            }
            if (app.repForegroundActivities != app.foregroundActivities) {
                app.repForegroundActivities = app.foregroundActivities;
                changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
            }
            if (app.repProcState != app.curProcState) {
                app.repProcState = app.curProcState;
                changes |= ProcessChangeItem.CHANGE_PROCESS_STATE;
                if (app.thread != null) {
                    try {
                        if (false) {
                            //RuntimeException h = new RuntimeException("here");
                            Slog.i(TAG, "Sending new process state " + app.repProcState
                                    + " to " + app /*, h*/);
                        }
                        app.thread.setProcessState(app.repProcState);
                    } catch (RemoteException e) {
                    }
                }
            }
            if (app.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT
                    || ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) {
                if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
                    // Experimental code to more aggressively collect pss while
                    // running test...  the problem is that this tends to collect
                    // the data right when a process is transitioning between process
                    // states, which well tend to give noisy data.
                    long start = SystemClock.uptimeMillis();
                    long pss = Debug.getPss(app.pid, mTmpLong, null);
                    recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
                    mPendingPssProcesses.remove(app);
                    Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                            + " to " + app.curProcState + ": "
                            + (SystemClock.uptimeMillis()-start) + "ms");
                }
                app.lastStateTime = now;
                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
                        mTestPssMode, isSleeping(), now);
                if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                        + ProcessList.makeProcStateString(app.setProcState) + " to "
                        + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
                        + (app.nextPssTime-now) + ": " + app);
            } else {
                if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                        && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
                        mTestPssMode)))) {
                    requestPssLocked(app, app.setProcState);
                    app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
                            mTestPssMode, isSleeping(), now);
                } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
                        "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
            }
            if (app.setProcState != app.curProcState) {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                        "Proc state change of " + app.processName
                                + " to " + app.curProcState);
                boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
                boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE;
                if (setImportant && !curImportant) {
                    // This app is no longer something we consider important enough to allow to
                    // use arbitrary amounts of battery power.  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, nowElapsed);
                    }
                    app.lastCpuTime = app.curCpuTime;
                }
                // Inform UsageStats of important process state change
                // Must be called before updating setProcState
                maybeUpdateUsageStatsLocked(app, nowElapsed);
                app.setProcState = app.curProcState;
                if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                    app.notCachedSinceIdle = false;
                }
                if (!doingAll) {
                    setProcessTrackerStateLocked(app, mProcessStats.getMemFactorLocked(), now);
                } else {
                    app.procStateChanged = true;
                }
            } else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime)
                    > USAGE_STATS_INTERACTION_INTERVAL) {
                // For apps that sit around for a long time in the interactive state, we need
                // to report this at least once a day so they don't go idle.
                maybeUpdateUsageStatsLocked(app, nowElapsed);
            }
            if (changes != 0) {
                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                        "Changes in " + app + ": " + changes);
                int i = mPendingProcessChanges.size()-1;
                ProcessChangeItem item = null;
                while (i >= 0) {
                    item = mPendingProcessChanges.get(i);
                    if (item.pid == app.pid) {
                        if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                                "Re-using existing item: " + item);
                        break;
                    }
                    i--;
                }
                if (i < 0) {
                    // No existing item in pending changes; need a new one.
                    final int NA = mAvailProcessChanges.size();
                    if (NA > 0) {
                        item = mAvailProcessChanges.remove(NA-1);
                        if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                                "Retrieving available item: " + item);
                    } else {
                        item = new ProcessChangeItem();
                        if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                                "Allocating new item: " + item);
                    }
                    item.changes = 0;
                    item.pid = app.pid;
                    item.uid = app.info.uid;
                    if (mPendingProcessChanges.size() == 0) {
                        if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                                "*** Enqueueing dispatch processes changed!");
                        mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
                    }
                    mPendingProcessChanges.add(item);
                }
                item.changes |= changes;
                item.processState = app.repProcState;
                item.foregroundActivities = app.repForegroundActivities;
                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                        "Item " + Integer.toHexString(System.identityHashCode(item))
                        + " " + app.toShortString() + ": changes=" + item.changes
                        + " procState=" + item.processState
                        + " foreground=" + item.foregroundActivities
                        + " type=" + app.adjType + " source=" + app.adjSource
                        + " target=" + app.adjTarget);
            }
            return success;
        }
        private final void enqueueUidChangeLocked(UidRecord uidRec, boolean gone) {
            if (uidRec.pendingChange == null) {
                if (mPendingUidChanges.size() == 0) {
                    if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                            "*** Enqueueing dispatch uid changed!");
                    mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_MSG).sendToTarget();
                }
                final int NA = mAvailUidChanges.size();
                if (NA > 0) {
                    uidRec.pendingChange = mAvailUidChanges.remove(NA-1);
                    if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                            "Retrieving available item: " + uidRec.pendingChange);
                } else {
                    uidRec.pendingChange = new UidRecord.ChangeItem();
                    if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                            "Allocating new item: " + uidRec.pendingChange);
                }
                uidRec.pendingChange.uidRecord = uidRec;
                uidRec.pendingChange.uid = uidRec.uid;
                mPendingUidChanges.add(uidRec.pendingChange);
            }
            uidRec.pendingChange.gone = gone;
            uidRec.pendingChange.processState = uidRec.setProcState;
        }
    

    NEXT:http://www.jianshu.com/p/94d1cd553c44

    相关文章

      网友评论

          本文标题:Android 进程优先级和 LowMemoryKiller 机

          本文链接:https://www.haomeiwen.com/subject/uqadmttx.html