Gestion des processus Android 1 - réglage de la priorité

priorité adj.

1. Classification du processus de candidature Android

Android divise le processus de candidature en cinq catégories, à savoir Forground, Visible, Service, Background et Empty.

  1. Classe de premier plan

Les processus de cette catégorie sont de la plus haute importance et les processus appartenant à cette catégorie incluent les situations suivantes :

  • Contient une activité frontale (c'est-à-dire que la fonction onResume a été appelée ou l'activité actuellement affichée).
  • Contient un service et le service est lié à une activité frontale (par exemple, l'application Musique comprend une interface frontale et un service de lecture, lorsque nous utilisons l'interface Musique tout en écoutant des chansons, le service est lié à une activité frontale).
  • Contient un service qui a appelé startForground, ou le service du processus appelle une fonction de son cycle de vie (onCreate, onStart ou onDestroy).
  • Le dernier cas est qu'une instance de BroadcastReceiver exécute la fonction onReceive dans le processus.
  1. Classe visible

    Il n'y a pas de composants frontaux dans le processus, mais l'utilisateur peut toujours les voir, comme l'interface d'activité derrière une boîte de dialogue. Il existe actuellement deux types de processus :

  • Le processus contient une Activity dont seule onPause est appelée (c'est-à-dire qu'elle est toujours au premier plan, mais qu'une partie de l'interface est couverte).
  • Ou contenir un service, et le service est lié à une activité visible (ou Forground) (littéralement, cette situation n'est pas très bonne à distinguer de la deuxième situation dans le processus Forground). (3) Classe de service, classe d'arrière-plan et classe vide

Aucun des trois types de processus n'a de parties visibles, comme suit.

  1. **Processus de service :** Ce type de processus contient un service. Ce service est démarré par startService et n'appartient pas aux deux types de processus précédents. Ce type de processus fonctionne généralement silencieusement en arrière-plan, comme le MediaScannerService présenté précédemment.
  2. **Processus en arrière-plan :** Ce type de processus contient des activités actuellement invisibles (c'est-à-dire que leur onStop a été appelé). Le système conserve ces processus dans une liste LRU (le moins récemment utilisé). Lorsque le système a besoin de récupérer de la mémoire, les processus les moins récemment utilisés de cette liste sont tués.
  3. **Processus vide :** Ce type de processus ne contient aucun composant. Pourquoi existe-t-il un tel processus qui n'inclut aucun composant? En fait, c'est très simple, en supposant que le processus ne crée qu'une seule activité, et après avoir terminé son travail, il appelle activement la fonction de finition pour se détruire (détruire), puis le processus deviendra un processus vide. La raison pour laquelle le système conserve le processus Empty est que lorsqu'ils sont à nouveau nécessaires (par exemple, l'utilisateur les démarre via startActivity dans un autre processus), il peut économiser une série de travaux longs et difficiles tels que le processus de fork et la création d'un environnement d'exploitation Android. .

Grâce à l'introduction ci-dessus, on peut constater que lorsqu'un certain processus est lié à l'affichage frontal, son importance est relativement élevée, ce qui peut être une preuve très directe que Google attache de l'importance à l'expérience utilisateur.

cinq ou quatre douteux

developer.android.com/guide/compo…

2. Concepts associés de la priorité des processus Android

2.1 Niveau oom_score_adj

Pour chaque processus en cours d'exécution, le noyau Linux expose /proc/[pid]/oom_score_adjun tel fichier via le système de fichiers proc pour permettre à d'autres programmes de modifier la priorité du processus spécifié. La plage de valeurs autorisée pour ce fichier est : entre -1000 et +1001. Des valeurs plus petites indiquent des processus plus importants. Lorsque la mémoire est très restreinte, le système parcourt tous les processus pour déterminer quel processus doit être tué pour récupérer de la mémoire, puis lit oom_score_adjla valeur de ce fichier.

PS : Dans les versions antérieures à Linux 2.6.36, le fichier fourni par Linux pour ajuster la priorité est /proc/[pid]/oom_adj. La plage de valeurs autorisées dans ce fichier est comprise entre -17 et +15. Des nombres inférieurs indiquent des processus plus importants. Ce fichier est obsolète dans les nouvelles versions de Linux. Mais vous pouvez toujours utiliser ce fichier. Lorsque vous modifiez ce fichier, le noyau convertira directement et reflétera le résultat dans le fichier oom_score_adj. L'implémentation des versions antérieures d'Android reposait également sur le fichier oom_adj. Mais dans la nouvelle version, il a été changé pour utiliser le fichier oom_score_adj.

Pour la commodité de la gestion, les valeurs possibles de sont prédéfinies dans ProcessList.java oom_score_adj, et les valeurs prédéfinies ici sont également une classification des processus d'application.


// 这是一个仅托管不可见活动的进程,因此它可以在没有任何干扰的情况下被终止。
static final int CACHED_APP_MAX_ADJ = 999;
static final int CACHED_APP_MIN_ADJ = 900;

// 这是我们允许首先退出的oom_adj级别。除非正在为进程分配oom_score_adj等于CACHED_APP_MAX_ADJ,
// 否则它不能等于CACHED_APP_MAX_ADJ。
static final int CACHED_APP_LMK_FIRST_ADJ = 950;

// SERVICE_ADJ的B列表-这些是旧的和老化的服务,不如A列表中的服务那么好看。
static final int SERVICE_B_ADJ = 800;

// 这是用户之前使用过的应用程序的进程。该进程保持在其他内容之上,因**为切换回先前的应用程**序非常常见。
这对于最近的任务切换(在两个最近的应用程序之间切换)以及正常的UI流非常重要,
例如在电子邮件应用程序中点击URI以在浏览器中查看,然后按返回键返回到电子邮件。
static final int PREVIOUS_APP_ADJ = 700;

// 这是托管主页应用程序的进程-即使它通常处于后台状态,我们也要尽量避免杀死它,因为用户与之交互非常频繁。
static final int HOME_APP_ADJ = 600;

// 这是托管应用程序服务的进程-杀死它不会对用户产生太大影响。
static final int SERVICE_ADJ = 500;

// 这是具有重型应用程序的进程。它在后台运行,但我们希望尽量避免杀死它。
在启动时在system/rootdir/init.rc中设置的值。
static final int HEAVY_WEIGHT_APP_ADJ = 400;

// 这是目前正在进行备份操作的进程。杀死它并不完全致命,但通常不是一个好主意。
static final int BACKUP_APP_ADJ = 300;

// 这是由系统(或其他应用程序)绑定的进程,比服务更重要,但不会立即影响用户如果被杀死。
static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

// 这是仅托管对用户可见组件的进程,并且我们确实希望避免杀死它们,但它们不是立即可见的。
// 例如,后台音乐播放就是一个例子。
static final int PERCEPTIBLE_APP_ADJ = 200;

// 这是仅托管对用户可见活动的进程,因此我们希望它们不会消失。
static final int VISIBLE_APP_ADJ = 100;
//200 -100 -1
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

// 这是最近处于前景应用程序并移动到FGS的进程。在一段时间内,继续将其视为几乎与前台应用程序相同。
// @see TOP_TO_FGS_GRACE_PERIOD
static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

// 运行当前前台应用程序的进程。是普通应用程序能够获取到的最高优先级。
static final int FOREGROUND_APP_ADJ = 0;

// 系统或持久进程绑定到的进程,并指出它很重要。
static final int PERSISTENT_SERVICE_ADJ = -700;

// 这是一个系统持久进程,例如电话。绝对不希望杀死它,但这样做并不完全致命。
static final int PERSISTENT_PROC_ADJ = -800;

// 系统进程以默认调整运行。
static final int SYSTEM_ADJ = -900;

// 用于原生进程的特殊代码,这些进程不受系统管理(因此系统不会分配oom adj)。
static final int NATIVE_ADJ = -1000;

quelques niveaux d'ajustement importants

FOREGROUND_APP_ADJ = 0C'est la priorité la plus élevée que les applications ordinaires peuvent obtenir.

VISIBLE_APP_ADJC'est la priorité du processus d'activité visible : en même temps, une seule activité n'est pas nécessairement visible, si l'activité de premier plan a un ensemble d'attributs transparents, alors l'activité derrière elle est également visible.

PERCEPTIBLE_APP_ADJIl fait référence aux processus qui peuvent être perçus par l'utilisateur, et les processus perceptibles incluent :

  • Le processus contient des activités qui sont en état de pause ou en pause
  • Le processus contient l'activité en cours d'arrêt
  • Le processus contient le service de premier plan

HEAVY_WEIGHT_APP_ADJLes processus lourds décrits font référence aux processus d'application qui ne peuvent pas enregistrer l'état via Manifest.

De plus, dans le système Android, certaines applications système résident en mémoire. Ces applications font généralement partie de l'implémentation du système. Si elles n'existent pas, le système sera dans un état étrange, tel que SystemUI (barre d'état, Keyguard sont dans cette application).

Ils sont donc prioritaires sur tous les processus applicatifs : PERSISTENT_SERVICE_ADJ = -700, PERSISTENT_PROC_ADJ = -800.

De plus, il existe certaines implémentations de services système. Si ces services système n'existent pas, le système ne fonctionnera pas, ces applications ont donc la priorité la plus élevée et doivent exister presque à tout moment : SYSTEM_ADJ = -900, NATIVE_ADJ = -1000.

2.2 Propriétés impliquant oom_score_adj dans ProcessRecord

**ProcessRecord.java**
//用于LRU列表控制
long lastActivityTime;   // For managing the LRU list
long lruWeight;      // Weight for ordering in LRU list
//和oom_adj有关
int maxAdj;           // Maximum OOM adjustment for thisprocess
int hiddenAdj;       // If hidden, this is the adjustment touse
int curRawAdj;       // Current OOM unlimited adjustment forthis process
int setRawAdj;       // Last set OOM unlimited adjustment forthis process
int curAdj;           // Current OOM adjustment for thisprocess
int setAdj;           // Last set OOM adjustment for thisprocess
//和调度优先级有关
int curSchedGroup;   // Currently desired scheduling class
int setSchedGroup;   // Last set to background scheduling class
//回收内存级别,见后文解释
int trimMemoryLevel; // Last selected memorytrimming level
//判断该进程的状态,主要和其中运行的Activity,Service有关
boolean keeping;     // Actively running code sodon't kill due to that?
boolean setIsForeground;    // Running foreground UI when last set?
boolean foregroundServices; // Running anyservices that are foreground?
boolean foregroundActivities; // Running anyactivities that are foreground?
boolean systemNoUi;   // This is a system process, but notcurrently showing UI.
boolean hasShownUi;  // Has UI been shown in this process since itwas started?
boolean pendingUiClean;     // Want to clean up resources from showingUI?
boolean hasAboveClient;     // Bound using BIND_ABOVE_CLIENT, so wantto be lower
//是否处于系统BadProcess列表
boolean bad;                // True if disabled in the badprocess list
//描述该进程因为是否有太多后台组件而被杀死
boolean killedBackground;   // True when proc has been killed due to toomany bg
String waitingToKill;       // Process is waiting to be killed whenin the bg; reason
//序号,每次调节进程优先级或者LRU列表位置时,这些序号都会递增
int adjSeq;                 // Sequence id for identifyingoom_adj assignment cycles
int lruSeq;                 // Sequence id for identifyingLRU update cycles

2.2.1 État du processus

L'état du processus affectera l'allocation de mémoire et la stratégie de récupération de place de la machine virtuelle pour le processus. Les attributs suivants dans ProcessRecord enregistrent l'état du processus :

En conséquence, la division du niveau process_state est redéfinie dans ActivityManager, et le système Android mettra à jour oom_score_adjla classification de l'état du processus tout en le modifiant :

[Le transfert d'image du lien externe a échoué, le site source peut avoir un mécanisme de lien antivol, il est recommandé d'enregistrer l'image et de la télécharger directement (img-QmcyHg5L-1688460965268)(https://link.juejin.cn/?target =http%3A%2F% 2Fimages.notend.cn%2F2018-03-15-18-03-57.png "http://images.notend.cn/2018-03-15-18-03-57.png ”)]

2.2.2 ScheduleGroup

Le noyau est responsable de la planification CPU du processus, et tous les processus en cours d'exécution ne peuvent pas obtenir des tranches de temps égales de la même manière. Dans ProcessRecord, le groupe de planification du processus est enregistré via le groupe de planification :

Process.javaCorrespondant au groupement de processus sous-jacent, en plus de la définition des différents groupes de threads définis ci-dessus , Activity managerun groupement de planification similaire est également défini pour , qui a également une relation correspondante avec la définition de groupement de threads précédente :

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

// Activity manager's version of Process.THREAD_GROUP_BACKGROUND
    static final int SCHED_GROUP_BACKGROUND = 0;
      // Activity manager's version of Process.THREAD_GROUP_RESTRICTED
    static final int SCHED_GROUP_RESTRICTED = 1;
    // Activity manager's version of Process.THREAD_GROUP_DEFAULT
    static final int SCHED_GROUP_DEFAULT = 2;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    public static final int SCHED_GROUP_TOP_APP = 3;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    // Disambiguate between actual top app and processes bound to the top app
    static final int SCHED_GROUP_TOP_APP_BOUND = 4;

valeur ActivityManager.java ProcessList.java
0 Processus.THREAD_GROUP_BACKGROUND SCHED_GROUP_BACKGROUND
1 Processus.THREAD_GROUP_RESTRICTED SCHED_GROUP_RESTRICTED
2 Processus.THREAD_GROUP_DEFAULT SCHED_GROUP_DEFAULT
3 Processus.THREAD_GROUP_TOP_APP SCHED_GROUP_TOP_APP
4 Processus.THREAD_GROUP_TOP_APP SCHED_GROUP_TOP_APP_BOUND

3. Changement de priorité du processus Android

La priorité d'un processus reflète le jugement du système sur l'importance du processus.

Dans le système Android, la priorité d'un processus affecte les trois facteurs suivants :

  • Lorsque la mémoire est restreinte, la stratégie de récupération du système pour le processus
  • La politique de planification du processeur du système pour le processus
  • La stratégie d'allocation de mémoire et de récupération de place de la machine virtuelle pour le processus

Nous savons que les changements dans la priorité d'un processus d'application Android sont liés aux changements dans le cycle de vie des composants de l'application Android. L'algorithme adj de planification de processus Android répertorie tous les événements qui déclencheront des changements dans l'état du processus, notamment :

Composants nom de la méthode décrire
Activité realStartActivityLockedrealStartActivityLocked Démarrer l'activité
resumeTopActivityInnerLocked Restaurer l'activité supérieure de la pile
finishCurrentActivityLocked Terminer l'activité en cours
destroyActivityLocked Détruire l'activité en cours
Service realStartServiceLockedrealStartServiceLocked démarrer le service
bindServiceLocked Service de liaison (ne mettre à jour que l'application actuelle)
unbindServiceLockedunbindServiceLocked Dissocier le service (ne mettre à jour que l'application actuelle)
bringDownServiceLocked Mettre fin au service (ne mettre à jour que l'application actuelle)
sendServiceArgsLocked Appelé lors du démarrage ou du service de nettoyage (ne mettez à jour que l'application actuelle)
Diffuser BQ.processNextBroadcast Gérer la prochaine diffusion
BQ.processCurBroadcastLocked Gérer la diffusion en cours
BQ.deliverToRegisteredReceiverLocked Distribuer les diffusions enregistrées (ne mettre à jour que l'application actuelle)
Fournisseur de contenu AMS.removeContentProvider supprimer le fournisseur
AMS.publishContentProviders Libérer le fournisseur (ne mettre à jour que l'application actuelle)
AMS.getContentProviderImpl Obtenez le fournisseur (ne mettez à jour que l'application actuelle)
Processus setSystemProcess Créer et configurer un processus système
addAppLocked Créer un processus persistant
attachApplicationLocked Le processus d'attachement à system_server après la création du processus
trimApplications Effacer les applications inutilisées
appDiedLocked le processus est mort
killAllBackgroundProcess Tuez tous les processus d'arrière-plan (processus normaux avec ADJ> 9 ou supprimé = vrai)
killPackageProcessesLocked Tuer les processus associés sous la forme d'un nom de package

Ce qui précède appellera directement ou indirectement la méthode dans AMS updateOomAdjLockedpour mettre à jour la priorité du processus, et finalement le réalisera dans la classe OomAdjuster.java.

3.1 OomAdjusterupdateOomAdjLocked

Il existe principalement les deux méthodes suivantes responsables de la mise à jour de la priorité du processus

void updateOomAdjLocked(String oomAdjReason) pour tous les processus

boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll, String oomAdjReason) {pour un seul processus

3.1.1 Ajuster adj updateOomAdjLocked pour un seul processus

code correspondant


    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord TOP_APP, boolean doingAll, long now) {
        if (app.thread == null) {
            return false;
        }

        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);

        return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
    }

3.1.2 calculateOomAdjLocked

computeOomAdjLockedLa méthode se charge de calculer la priorité du processus, soit environ 700 lignes au total, ce qui est trop long. Le petit résumé consiste à mettre à jour adj, procstate et schedgruop en fonction des différents états du processus. Il est résumé dans la figure ci-dessous. Il n'y a pas de vérification un par un, le code réel prévaudra.

Priorité de processus.png

3.1.3 appliquerOomAdjLocké

  1. Traiter la compression de la mémoire AppCompactor en fonction des modifications apportées
  2. Mettez à jour l'oom adj du processus et écrivez à lmkd via le socket
  3. Mettre à jour le groupe de planification
  • Tuez le processus bg qui doit être tué. Si waitToKill n'est pas nul (waitingToKill = raison), le récepteur est vide et SCHED_GROUP_BACKGROUND
  • Selon la relation correspondante entre les deux groupes de ProcessList.java ActivityManager.java, passez enfin setProcessGroup(pid, group); mettez à jour le groupe et contactez le côté supérieur pour voir.
  1. Pour le processus qui devient le premier plan ou change du premier plan, effectuez une conversion RT et FIFO, et modifiez la priorité et la stratégie en temps réel via scheduleAsFifoPriority et setThreadPriority
  2. Update nextPssTime, cette valeur correspond à la prochaine mise à jour de PSS.
  3. Par rapport à PROCESS_STATE_SERVICE, jugez s'il s'agit d'un processus important
  4. L'état memFactor du nouveau processus unique, cette valeur est liée à la mémoire de coupe
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
    @GuardedBy("mService")
    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
            long nowElapsed) {
        boolean success = true;

        if (app.getCurRawAdj() != app.setRawAdj) {
            app.setRawAdj = app.getCurRawAdj();
        }
        int changes = 0;

        // don't compact during bootup
	      //1.内存压缩相关逻辑
        if (mAppCompact.useCompaction() && mService.mBooted) {
            // Cached and prev/home compaction
            if (app.curAdj != app.setAdj) {
                // Perform a minor compaction when a perceptible app becomes the prev/home app
                // Perform a major compaction when any app enters cached
                // reminder: here, setAdj is previous state, curAdj is upcoming state
                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
                        (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                                app.curAdj == ProcessList.HOME_APP_ADJ)) {
                    mAppCompact.compactAppSome(app);
                } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
                                || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
                        && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
                        && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
                    mAppCompact.compactAppFull(app);
                }
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
                    && app.setAdj < ProcessList.FOREGROUND_APP_ADJ
                    // Because these can fire independent of oom_adj/procstate changes, we need
                    // to throttle the actual dispatch of these requests in addition to the
                    // processing of the requests. As a result, there is throttling both here
                    // and in AppCompactor.
                    && mAppCompact.shouldCompactPersistent(app, now)) {
                mAppCompact.compactAppPersistent(app);
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
                    && app.getCurProcState()
                        == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                    && mAppCompact.shouldCompactBFGS(app, now)) {
                mAppCompact.compactAppBfgs(app);
            }
        }
				//2.设置进程的oomadj
        if (app.curAdj != app.setAdj) {
            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
                String msg = "Set " + app.pid + " " + app.processName + " adj "
                        + app.curAdj + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
            app.setAdj = app.curAdj;
            app.verifiedAdj = ProcessList.INVALID_ADJ;
        }

        final int curSchedGroup = app.getCurrentSchedulingGroup();
	//3.更新进程SchedGroup,判断进程是否需要被杀
        if (app.setSchedGroup != curSchedGroup) {
            int oldSchedGroup = app.setSchedGroup;
            app.setSchedGroup = curSchedGroup;
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
                String msg = "Setting sched group of " + app.processName
                        + " to " + curSchedGroup + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
//如果waitingToKill不为null(waitingToKill =reason),receiver为空并且为SCHED_GROUP_BACKGROUND
则被杀
            if (app.waitingToKill != null && app.curReceivers.isEmpty()
                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                app.kill(app.waitingToKill, true);
                success = false;
            } else {
                int processGroup;
                switch (curSchedGroup) {
                    case ProcessList.SCHED_GROUP_BACKGROUND:
                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
                        break;
                    case ProcessList.SCHED_GROUP_TOP_APP:
                    case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
                        processGroup = THREAD_GROUP_TOP_APP;
                        break;
                    case ProcessList.SCHED_GROUP_RESTRICTED:
                        processGroup = THREAD_GROUP_RESTRICTED;
                        break;
                    default:
                        processGroup = THREAD_GROUP_DEFAULT;
                        break;
                }
                mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
                        0 /* unused */, app.pid, processGroup));
//4.对于变成前台或者从前台变化的进程,进行RT和FIFO的变换,通过scheduleAsFifoPriority和setThreadPriority
更改优先级和实时策略
                try {
                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                        // do nothing if we already switched to RT
                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                            app.getWindowProcessController().onTopProcChanged();
                            if (mService.mUseFifoUiScheduling) {
                                // Switch UI pipeline for app to SCHED_FIFO
                                app.savedPriority = Process.getThreadPriority(app.pid);
                                mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
                                if (app.renderThreadTid != 0) {
                                    mService.scheduleAsFifoPriority(app.renderThreadTid,
                                            /* suppressLogs */true);
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
                                                app.renderThreadTid + ") to FIFO");
                                    }
                                } else {
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Not setting RenderThread TID");
                                    }
                                }
                            } else {
                                // Boost priority for top app UI and render threads
                                setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
                                if (app.renderThreadTid != 0) {
                                    try {
                                        setThreadPriority(app.renderThreadTid,
                                                TOP_APP_PRIORITY_BOOST);
                                    } catch (IllegalArgumentException e) {
                                        // thread died, ignore
                                    }
                                }
                            }
                        }
                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                        app.getWindowProcessController().onTopProcChanged();
                        if (mService.mUseFifoUiScheduling) {
                            try {
                                // Reset UI pipeline to SCHED_OTHER
                                setThreadScheduler(app.pid, SCHED_OTHER, 0);
                                setThreadPriority(app.pid, app.savedPriority);
                                if (app.renderThreadTid != 0) {
                                    setThreadScheduler(app.renderThreadTid,
                                            SCHED_OTHER, 0);
                                    setThreadPriority(app.renderThreadTid, -4);
                                }
                            } catch (IllegalArgumentException e) {
                                Slog.w(TAG,
                                        "Failed to set scheduling policy, thread does not exist:\n"
                                                + e);
                            } catch (SecurityException e) {
                                Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
                            }
                        } else {
                            // Reset priority for top app UI and render threads
                            setThreadPriority(app.pid, 0);
                            if (app.renderThreadTid != 0) {
                                setThreadPriority(app.renderThreadTid, 0);
                            }
                        }
                    }
                } catch (Exception e) {
                    if (DEBUG_ALL) {
                        Slog.w(TAG, "Failed setting thread priority of " + app.pid, e);
                    }
                }
            }
        }
        if (app.repForegroundActivities != app.hasForegroundActivities()) {
            app.repForegroundActivities = app.hasForegroundActivities();
            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
        }
        if (app.getReportedProcState() != app.getCurProcState()) {
            app.setReportedProcState(app.getCurProcState());
            if (app.thread != null) {
                try {
                    if (false) {
                        //RuntimeException h = new RuntimeException("here");
                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
                                + " to " + app /*, h*/);
                    }
                    app.thread.setProcessState(app.getReportedProcState());
                } catch (RemoteException e) {
                }
            }
        }
//5.如果进程setProcState等于PROCESS_STATE_NONEXISTENT,或者和内存记录的ProcState对比有变化
更新nextPssTime
        if (app.setProcState == PROCESS_STATE_NONEXISTENT
                || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
            if (false && mService.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 will tend to give noisy data.
                long start = SystemClock.uptimeMillis();
                long startTime = SystemClock.currentThreadTimeMillis();
                long pss = Debug.getPss(app.pid, mTmpLong, null);
                long endTime = SystemClock.currentThreadTimeMillis();
                mService.recordPssSampleLocked(app, app.getCurProcState(), pss,
                        mTmpLong[0], mTmpLong[1], mTmpLong[2],
                        ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
                mService.mPendingPssProcesses.remove(app);
                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                        + " to " + app.getCurProcState() + ": "
                        + (SystemClock.uptimeMillis()-start) + "ms");
            }
            app.lastStateTime = now;
            app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                    app.procStateMemTracker, mService.mTestPssMode,
                    mService.mAtmInternal.isSleeping(), now);
            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                    + ProcessList.makeProcStateString(app.setProcState) + " to "
                    + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
                    + (app.nextPssTime-now) + ": " + app);
        } else {
            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                    && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
                    mService.mTestPssMode)))) {
                if (mService.requestPssLocked(app, app.setProcState)) {
                    app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                            app.procStateMemTracker, mService.mTestPssMode,
                            mService.mAtmInternal.isSleeping(), now);
                }
            } else if (false && DEBUG_PSS) {
                Slog.d(TAG_PSS,
                        "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
            }
        }
        if (app.setProcState != app.getCurProcState()) {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
                String msg = "Proc state change of " + app.processName
                        + " to " + ProcessList.makeProcStateString(app.getCurProcState())
                        + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
//6.判断是否是重要进程
            boolean setImportant = app.setProcState < PROCESS_STATE_SERVICE;
            boolean curImportant = app.getCurProcState() < 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 CPU time to later know to
                // kill it if it is not behaving well.
                app.setWhenUnimportant(now);
                app.lastCpuTime = 0;
            }
            // Inform UsageStats of important process state change
            // Must be called before updating setProcState
            maybeUpdateUsageStatsLocked(app, nowElapsed);

            maybeUpdateLastTopTime(app, now);

            app.setProcState = app.getCurProcState();
            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                app.notCachedSinceIdle = false;
            }
//7.更新单个进程的memFactor状态,这个值和trim memory相关
            if (!doingAll) {
                mService.setProcessTrackerStateLocked(app,
                        mService.mProcessStats.getMemFactorLocked(), now);
            } else {
                app.procStateChanged = true;
            }
        } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
                > mConstants.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);
        } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
                > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
            // For foreground services that sit around for a long time but are not interacted with.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        }

        if (changes != 0) {
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Changes in " + app + ": " + changes);
            ActivityManagerService.ProcessChangeItem item =
                    mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
            item.changes = changes;
            item.foregroundActivities = app.repForegroundActivities;
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Item " + Integer.toHexString(System.identityHashCode(item))
                            + " " + app.toShortString() + ": changes=" + item.changes
                            + " foreground=" + item.foregroundActivities
                            + " type=" + app.adjType + " source=" + app.adjSource
                            + " target=" + app.adjTarget);
        }

        return success;
    }

3.2 updateOomAdjLocked(String oomAdjReason) pour tous les processus

Pour les scénarios liés à oomAdjReason, reportez-vous au tableau ci-dessous.

nom constant journal de bord décrire
OOM_ADJ_REASON_NONE mettre à jourOomAdj_meh Aucune cause de réglage OOM spécifique
OOM_ADJ_REASON_ACTIVITY updateOomAdj_activityChange Mise à jour OOM Adj causée par un changement d'activité
OOM_ADJ_REASON_FINISH_RECEIVER updateOomAdj_finishReceiver Mettre fin à la mise à jour OOM Adj causée par Receiver
OOM_ADJ_REASON_START_RECEIVER updateOomAdj_startReceiver Mise à jour OOM Adj causée par le démarrage de Receiver
OOM_ADJ_REASON_BIND_SERVICE updateOomAdj_bindService Mise à jour OOM Adj causée par la liaison du service
OOM_ADJ_REASON_UNBIND_SERVICE updateOomAdj_unbindService 解绑 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_START_SERVICE updateOomAdj_startService 启动 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_GET_PROVIDER updateOomAdj_getProvider 获取 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_REMOVE_PROVIDER updateOomAdj_removeProvider 移除 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_UI_VISIBILITY updateOomAdj_uiVisibility UI 可见性变化导致的 OOM Adj 更新
OOM_ADJ_REASON_WHITELIST updateOomAdj_whitelistChange 白名单变化导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_BEGIN updateOomAdj_processBegin 进程启动导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_END updateOomAdj_processEnd 进程结束导致的 OOM Adj 更新

代码太长了贴不动了。之后在分析吧

4.Process中对线程和进程的调度

frameworks/base/core/java/android/os/Process.java

/*
   设置线程的Group,实际上就是设置线程的调度策略,目前Android定义了三种Group。
   THREAD_GROUP_DEFAULT:Default thread group - gets a 'normal'share of the CPU
   THREAD_GROUP_BG_NONINTERACTIVE:Background non-interactive thread group.
   Allthreads in this group are scheduled with a reduced share of the CPU
   THREAD_GROUP_FG_BOOST:Foreground 'boost' thread group - Allthreads in
   this group are scheduled with an increasedshare of the CPU.
   目前代码中还没有地方使用THREAD_GROUP_FG_BOOST这种Group
*/
public static final native void setThreadGroup(inttid, int group)
           throws IllegalArgumentException, SecurityException;

//设置进程的调度策略,包括该进程的所有线程
public static final native void setProcessGroup(int pid, int group)
           throws IllegalArgumentException, SecurityException;
设置线程的调度策略和优先级 针对tid。linux实现
public static final native void setThreadScheduler(int tid, int policy, int priority)
            throws IllegalArgumentException;
//设置线程的调度优先级
public static final native void setThreadPriority(int priority)
           throws IllegalArgumentException, SecurityException;

值得一提的是linux不区分进程和线程的概念。Android 中的线程对应到 Linux 内核可以看为轻量级进程,所以 Linux 为其分配资源适用 Linux 进程调度策略。其中主线程等同于应用进程的优先级。

我们为应用中各子线程设置的优先级,将直接影响到主线程在抢占各种系统资源尤其是 CPU 资源时候的优先级,所以为了保证主线程执行的顺畅,我们应尽量控制子线程的优先级。

在Android 中常见的几种异步方式 new Thread()、AysncTask、HandlerThread、ThreadPoolExecutor、IntentService。除了 AysncTask 以外,其他的创建线程的过程中,默认都是和当前线程(一般是 UI 线程)保持一样的优先级,只有 AysncTask 默认是 THREAD_PRIORITY_BACKGROUND 的优先级,所以为了保证主线程能够拥有较为优先的执行级别,建议在创建异步线程的过程中注意对优先级的控制。

5.总结

在 Android 应用状态发生变化以后,会导致进程的 oom_score_adjprocStateschedGroup 等进程状态的重新计算和设置,,并且通过 applyOomAdjLocked 方法将对应的优先级、adj、进程状态等值应用到进程上,从而改变进程的优先级和调度策略。以上的过程大概可以概括为:

  • 通过设置进程组,改变了进程所在 cgroup,

  • 通过设置调度策略实现主线程在实时优先级和普通优先级的切换,

  • 通过设置优先级改变进程 nice 值,同时在底层会改变进程所在的 cgroup。

image.png

延伸问题

  1. 什么是cgroup、线程调度策略的区别,线程优先级的应用?
  2. adj更新和lmkd是如何配合?

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
insérez la description de l'image ici
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

insérez la description de l'image ici
二、源码解析合集
insérez la description de l'image ici

3. La collection de frameworks open source
insérez la description de l'image ici
invite tout le monde à prendre en charge en un clic et trois liens. Si vous avez besoin des informations contenues dans l'article, cliquez simplement sur la carte WeChat de certification officielle CSDN à la fin de l'article pour l'obtenir gratuitement↓↓↓

Je suppose que tu aimes

Origine blog.csdn.net/Eqiqi/article/details/131538782
conseillé
Classement